summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--3rdparty/ymfm/.editorconfig9
-rw-r--r--3rdparty/ymfm/.gitignore39
-rw-r--r--3rdparty/ymfm/GeneralInfo.md282
-rw-r--r--3rdparty/ymfm/LICENSE29
-rw-r--r--3rdparty/ymfm/README.md118
-rw-r--r--3rdparty/ymfm/buildall.cpp114
-rw-r--r--3rdparty/ymfm/examples/vgmrender/.gitignore1
-rw-r--r--3rdparty/ymfm/examples/vgmrender/em_inflate.cpp1185
-rw-r--r--3rdparty/ymfm/examples/vgmrender/em_inflate.h49
-rw-r--r--3rdparty/ymfm/examples/vgmrender/vgmrender.cpp1412
-rw-r--r--3rdparty/ymfm/src/ymfm.h486
-rw-r--r--3rdparty/ymfm/src/ymfm_adpcm.cpp (renamed from src/devices/sound/ymadpcm.cpp)459
-rw-r--r--3rdparty/ymfm/src/ymfm_adpcm.h411
-rw-r--r--3rdparty/ymfm/src/ymfm_fm.h449
-rw-r--r--3rdparty/ymfm/src/ymfm_fm.ipp1539
-rw-r--r--3rdparty/ymfm/src/ymfm_misc.cpp175
-rw-r--r--3rdparty/ymfm/src/ymfm_misc.h94
-rw-r--r--3rdparty/ymfm/src/ymfm_opl.cpp2207
-rw-r--r--3rdparty/ymfm/src/ymfm_opl.h902
-rw-r--r--3rdparty/ymfm/src/ymfm_opm.cpp535
-rw-r--r--3rdparty/ymfm/src/ymfm_opm.h320
-rw-r--r--3rdparty/ymfm/src/ymfm_opn.cpp2469
-rw-r--r--3rdparty/ymfm/src/ymfm_opn.h800
-rw-r--r--3rdparty/ymfm/src/ymfm_opq.cpp480
-rw-r--r--3rdparty/ymfm/src/ymfm_opq.h293
-rw-r--r--3rdparty/ymfm/src/ymfm_opz.cpp808
-rw-r--r--3rdparty/ymfm/src/ymfm_opz.h332
-rw-r--r--3rdparty/ymfm/src/ymfm_pcm.cpp712
-rw-r--r--3rdparty/ymfm/src/ymfm_pcm.h307
-rw-r--r--3rdparty/ymfm/src/ymfm_ssg.cpp279
-rw-r--r--3rdparty/ymfm/src/ymfm_ssg.h206
-rw-r--r--android-project/app/src/main/AndroidManifest.xml4
-rw-r--r--artwork/chess/README.md2
-rw-r--r--artwork/chess/bq.svg41
-rw-r--r--artwork/chess/wq.svg20
-rw-r--r--docs/source/initialsetup/compilingmame.rst118
-rw-r--r--docs/source/initialsetup/configuringmame.rst71
-rw-r--r--docs/source/initialsetup/index.rst4
-rw-r--r--docs/source/initialsetup/installingmame.rst12
-rw-r--r--docs/source/initialsetup/mameintro.rst118
-rw-r--r--docs/source/license.rst13
-rw-r--r--docs/source/techspecs/naming.rst2
-rw-r--r--docs/source/usingmame/mamemenus.rst4
-rw-r--r--docs/source/usingmame/usingmame.rst91
-rw-r--r--hash/a800.xml16
-rw-r--r--hash/a800_flop.xml223
-rw-r--r--hash/alphatro_cart.xml9
-rw-r--r--hash/alphatro_flop.xml20
-rw-r--r--hash/apple2_flop_clcracked.xml1609
-rw-r--r--hash/apple2_flop_orig.xml266
-rw-r--r--hash/apple2gs_flop_misc.xml (renamed from hash/apple2gs.xml)3
-rw-r--r--hash/apple2gs_flop_orig.xml2077
-rw-r--r--hash/aquarius_cart.xml104
-rw-r--r--hash/basf7100.xml31
-rw-r--r--hash/bbc_flop_32016.xml13
-rw-r--r--hash/bbc_rom.xml1663
-rw-r--r--hash/bml3_flop.xml89
-rw-r--r--hash/cc40_cart.xml18
-rw-r--r--hash/cgenie_cass.xml1624
-rw-r--r--hash/chessmstdm.xml9
-rw-r--r--hash/chip8_quik.xml12
-rw-r--r--hash/dragon_cart.xml38
-rw-r--r--hash/fmtowns_cd.xml2015
-rw-r--r--hash/fmtowns_flop_cracked.xml30
-rw-r--r--hash/fmtowns_flop_misc.xml199
-rw-r--r--hash/fmtowns_flop_orig.xml307
-rw-r--r--hash/gamegear.xml399
-rw-r--r--hash/ggm.xml17
-rw-r--r--hash/ibm5150.xml262
-rw-r--r--hash/ibm5170.xml270
-rw-r--r--hash/jakks_gamekey_sw.xml39
-rw-r--r--hash/juicebox.xml358
-rw-r--r--hash/leapfrog_leapster_explorer_cart.xml44
-rw-r--r--hash/leapfrog_zippity_cart.xml12
-rw-r--r--hash/leapster.xml747
-rw-r--r--hash/mac_hdflop.xml7439
-rw-r--r--hash/mbee_cart.xml654
-rw-r--r--hash/mbee_cass.xml55
-rw-r--r--hash/mbee_flop.xml5974
-rw-r--r--hash/mbee_quik.xml1964
-rw-r--r--hash/megadriv.xml472
-rw-r--r--hash/microvision.xml1
-rw-r--r--hash/mobigo_cart.xml55
-rw-r--r--hash/neogeo.xml5
-rw-r--r--hash/nes.xml1632
-rw-r--r--hash/pc98.xml407
-rw-r--r--hash/pc98_cd.xml8
-rw-r--r--hash/pce.xml652
-rw-r--r--hash/pce_tourvision.xml16
-rw-r--r--hash/pmd85_cass.xml2
-rw-r--r--hash/rx78_cart.xml33
-rw-r--r--hash/sagafox.xml19
-rw-r--r--hash/saitek_kso.xml2
-rw-r--r--hash/singingstarkaraoke_cart.xml2
-rw-r--r--hash/sms.xml166
-rw-r--r--hash/spectrum_cass.xml1928
-rw-r--r--hash/stv.xml3
-rw-r--r--hash/super80_cass.xml110
-rw-r--r--hash/ti74_cart.xml13
-rw-r--r--hash/ti95_cart.xml13
-rw-r--r--hash/trs80_cass.xml756
-rw-r--r--hash/trs80_flop.xml75
-rw-r--r--hash/trs80_quik.xml1155
-rw-r--r--hash/u110_card.xml199
-rw-r--r--hash/vgmplay.xml1400
-rw-r--r--hash/vic1001_cart.xml2
-rw-r--r--hash/vsmile_cart.xml45
-rw-r--r--hash/vtech_innotab_cart.xml27
-rw-r--r--hash/vtech_storio_cart.xml115
-rw-r--r--language/Afrikaans/strings.po3190
-rw-r--r--language/Albanian/strings.po3190
-rw-r--r--language/Arabic/strings.po3190
-rw-r--r--language/Basque/strings.po3190
-rw-r--r--language/Belarusian/strings.po3190
-rw-r--r--language/Bosnian/strings.po3190
-rw-r--r--language/Bulgarian/strings.po3190
-rw-r--r--language/Burmese/strings.po3190
-rw-r--r--language/Catalan/strings.po3914
-rw-r--r--language/Chinese_Simplified/strings.po4239
-rw-r--r--language/Chinese_Traditional/strings.po4239
-rw-r--r--language/Croatian/strings.po3190
-rw-r--r--language/Czech/strings.po4095
-rw-r--r--language/Danish/strings.po3190
-rw-r--r--language/Dutch/strings.po4373
-rw-r--r--language/English/strings.po3190
-rw-r--r--language/Estonian/strings.po3190
-rw-r--r--language/Finnish/strings.po3190
-rw-r--r--language/French/strings.po4240
-rw-r--r--language/French_Belgium/strings.po4027
-rw-r--r--language/French_Canada/strings.po3190
-rw-r--r--language/Georgian/strings.po3190
-rw-r--r--language/German/strings.po4330
-rw-r--r--language/Greek/strings.po4276
-rw-r--r--language/Hebrew/strings.po3190
-rw-r--r--language/Hindi/strings.po3190
-rw-r--r--language/Hungarian/strings.po4150
-rw-r--r--language/Indonesian/strings.po3190
-rw-r--r--language/Italian/strings.po4290
-rw-r--r--language/Japanese/strings.po4287
-rw-r--r--language/Korean/strings.po4316
-rw-r--r--language/Latvian/strings.po3190
-rw-r--r--language/Lithuanian/strings.po3190
-rw-r--r--language/Macedonian/strings.po3190
-rw-r--r--language/Norwegian/strings.po4321
-rw-r--r--language/Persian/strings.po3190
-rw-r--r--language/Polish/strings.po3190
-rw-r--r--language/Portuguese/strings.po4301
-rw-r--r--language/Portuguese_Brazil/strings.po4379
-rw-r--r--language/Romanian/strings.po3190
-rw-r--r--language/Russian/strings.po4269
-rw-r--r--language/Serbian/strings.po4147
-rw-r--r--language/Serbian_Cyrillic/strings.po4143
-rw-r--r--language/Slovak/strings.po3190
-rw-r--r--language/Slovenian/strings.po3190
-rw-r--r--language/Spanish/strings.po4321
-rw-r--r--language/Spanish_Mexico/strings.po3190
-rw-r--r--language/Swedish/strings.po4279
-rw-r--r--language/Thai/strings.po3190
-rw-r--r--language/Turkish/strings.po3879
-rw-r--r--language/Ukrainian/strings.po3190
-rw-r--r--language/Vietnamese/strings.po3190
-rw-r--r--makefile11
-rw-r--r--plugins/cheat/cheat_xml.lua2
-rw-r--r--plugins/console/init.lua54
-rw-r--r--plugins/data/data_history.lua1
-rw-r--r--scripts/genie.lua10
-rw-r--r--scripts/src/3rdparty.lua38
-rw-r--r--scripts/src/bus.lua106
-rw-r--r--scripts/src/cpu.lua14
-rw-r--r--scripts/src/formats.lua52
-rw-r--r--scripts/src/machine.lua72
-rw-r--r--scripts/src/main.lua1
-rw-r--r--scripts/src/osd/mac_cfg.lua2
-rw-r--r--scripts/src/osd/sdl_cfg.lua2
-rw-r--r--scripts/src/osd/windows.lua1
-rw-r--r--scripts/src/osd/windows_cfg.lua2
-rw-r--r--scripts/src/sound.lua141
-rw-r--r--scripts/src/tools.lua6
-rw-r--r--scripts/target/mame/arcade.lua52
-rw-r--r--scripts/target/mame/mess.lua132
-rw-r--r--scripts/target/mame/virtual.lua3
-rw-r--r--src/devices/bus/a2bus/a2bus.h1
-rw-r--r--src/devices/bus/a2bus/a2mockingboard.cpp107
-rw-r--r--src/devices/bus/a2bus/a2mockingboard.h51
-rw-r--r--src/devices/bus/a2bus/booti.cpp171
-rw-r--r--src/devices/bus/a2bus/booti.h58
-rw-r--r--src/devices/bus/a2bus/titan3plus2.cpp334
-rw-r--r--src/devices/bus/a2bus/titan3plus2.h64
-rw-r--r--src/devices/bus/a2gameio/gameio.h3
-rw-r--r--src/devices/bus/a2gameio/joystick.cpp2
-rw-r--r--src/devices/bus/a7800/xboard.h2
-rw-r--r--src/devices/bus/adb/a9m0330.cpp268
-rw-r--r--src/devices/bus/adb/a9m0330.h48
-rw-r--r--src/devices/bus/adb/a9m0331.cpp125
-rw-r--r--src/devices/bus/adb/a9m0331.h42
-rw-r--r--src/devices/bus/adb/adb.cpp6
-rw-r--r--src/devices/bus/adb/adb.h3
-rw-r--r--src/devices/bus/apricot/expansion/winchester.cpp1
-rw-r--r--src/devices/bus/bbc/1mhzbus/beebopl.h2
-rw-r--r--src/devices/bus/bbc/fdc/acorn.cpp26
-rw-r--r--src/devices/bus/bbc/fdc/acorn.h6
-rw-r--r--src/devices/bus/bbc/fdc/ams.cpp15
-rw-r--r--src/devices/bus/bbc/fdc/ams.h3
-rw-r--r--src/devices/bus/bbc/fdc/cumana.cpp19
-rw-r--r--src/devices/bus/bbc/fdc/cumana.h3
-rw-r--r--src/devices/bus/bbc/fdc/opus.cpp46
-rw-r--r--src/devices/bus/bbc/fdc/opus.h6
-rw-r--r--src/devices/bus/bbc/fdc/watford.cpp22
-rw-r--r--src/devices/bus/bbc/fdc/watford.h6
-rw-r--r--src/devices/bus/bbc/internal/cumana68k.cpp37
-rw-r--r--src/devices/bus/bbc/internal/cumana68k.h5
-rw-r--r--src/devices/bus/bbc/tube/tube.cpp6
-rw-r--r--src/devices/bus/bbc/tube/tube_32016.cpp2
-rw-r--r--src/devices/bus/bbc/tube/tube_80286.cpp2
-rw-r--r--src/devices/bus/bbc/tube/tube_arm7.cpp295
-rw-r--r--src/devices/bus/bbc/tube/tube_arm7.h92
-rw-r--r--src/devices/bus/bml3/bml3bus.h11
-rw-r--r--src/devices/bus/bml3/bml3mp1802.cpp1
-rw-r--r--src/devices/bus/bml3/bml3mp1805.cpp110
-rw-r--r--src/devices/bus/bml3/bml3mp1805.h10
-rw-r--r--src/devices/bus/c64/sfx_sound_expander.h2
-rw-r--r--src/devices/bus/cbus/pc9801_118.cpp2
-rw-r--r--src/devices/bus/cbus/pc9801_118.h2
-rw-r--r--src/devices/bus/cbus/pc9801_26.cpp2
-rw-r--r--src/devices/bus/cbus/pc9801_26.h2
-rw-r--r--src/devices/bus/cbus/pc9801_86.h2
-rw-r--r--src/devices/bus/cbus/pc9801_cbus.cpp11
-rw-r--r--src/devices/bus/centronics/chessmec.cpp8
-rw-r--r--src/devices/bus/centronics/ctronics.cpp6
-rw-r--r--src/devices/bus/centronics/digiblst.cpp6
-rw-r--r--src/devices/bus/centronics/digiblst.h2
-rw-r--r--src/devices/bus/centronics/smartboard.cpp37
-rw-r--r--src/devices/bus/centronics/smartboard.h40
-rw-r--r--src/devices/bus/coco/coco_fdc.cpp10
-rw-r--r--src/devices/bus/coco/coco_max.cpp170
-rw-r--r--src/devices/bus/coco/coco_max.h14
-rw-r--r--src/devices/bus/coco/coco_multi.cpp123
-rw-r--r--src/devices/bus/coco/coco_multi.h1
-rw-r--r--src/devices/bus/coco/coco_ssc.cpp47
-rw-r--r--src/devices/bus/coco/coco_wpk.cpp201
-rw-r--r--src/devices/bus/coco/coco_wpk.h94
-rw-r--r--src/devices/bus/coco/coco_wpk2p.cpp56
-rw-r--r--src/devices/bus/coco/coco_wpk2p.h41
-rw-r--r--src/devices/bus/coco/cococart.cpp67
-rw-r--r--src/devices/bus/coco/cococart.h3
-rw-r--r--src/devices/bus/coco/dragon_claw.cpp212
-rw-r--r--src/devices/bus/coco/dragon_claw.h59
-rw-r--r--src/devices/bus/coco/dragon_msx2.cpp191
-rw-r--r--src/devices/bus/coco/dragon_msx2.h53
-rw-r--r--src/devices/bus/coco/dragon_serial.cpp154
-rw-r--r--src/devices/bus/coco/dragon_serial.h52
-rw-r--r--src/devices/bus/electron/m2105.cpp200
-rw-r--r--src/devices/bus/electron/m2105.h13
-rw-r--r--src/devices/bus/epson_sio/pf10.cpp2
-rw-r--r--src/devices/bus/generic/slot.cpp4
-rw-r--r--src/devices/bus/generic/slot.h6
-rw-r--r--src/devices/bus/isa/adlib.h2
-rw-r--r--src/devices/bus/isa/ibm_mfc.cpp12
-rw-r--r--src/devices/bus/isa/ibm_mfc.h4
-rw-r--r--src/devices/bus/isa/isa_cards.cpp2
-rw-r--r--src/devices/bus/isa/lrk330.cpp130
-rw-r--r--src/devices/bus/isa/lrk330.h38
-rw-r--r--src/devices/bus/isa/sb16.h2
-rw-r--r--src/devices/bus/isa/sblaster.cpp2
-rw-r--r--src/devices/bus/isa/sblaster.h2
-rw-r--r--src/devices/bus/isa/stereo_fx.h2
-rw-r--r--src/devices/bus/mc10/mc10_cart.cpp230
-rw-r--r--src/devices/bus/mc10/mc10_cart.h118
-rw-r--r--src/devices/bus/mc10/mcx128.cpp371
-rw-r--r--src/devices/bus/mc10/mcx128.h15
-rw-r--r--src/devices/bus/mc10/pak.cpp69
-rw-r--r--src/devices/bus/mc10/pak.h37
-rw-r--r--src/devices/bus/mc10/ram.cpp78
-rw-r--r--src/devices/bus/mc10/ram.h14
-rw-r--r--src/devices/bus/megadrive/md_slot.h4
-rw-r--r--src/devices/bus/msx_cart/fmpac.h2
-rw-r--r--src/devices/bus/msx_cart/moonsound.h2
-rw-r--r--src/devices/bus/msx_cart/msx_audio.h2
-rw-r--r--src/devices/bus/msx_cart/yamaha.cpp23
-rw-r--r--src/devices/bus/msx_cart/yamaha.h4
-rw-r--r--src/devices/bus/msx_slot/music.h2
-rw-r--r--src/devices/bus/nes/act53.cpp66
-rw-r--r--src/devices/bus/nes/act53.h11
-rw-r--r--src/devices/bus/nes/konami.h2
-rw-r--r--src/devices/bus/nscsi/cd.cpp50
-rw-r--r--src/devices/bus/nscsi/cdu561.cpp87
-rw-r--r--src/devices/bus/nscsi/cdu561.h29
-rw-r--r--src/devices/bus/nscsi/cdu75s.cpp29
-rw-r--r--src/devices/bus/nscsi/crd254sh.cpp68
-rw-r--r--src/devices/bus/nscsi/crd254sh.h36
-rw-r--r--src/devices/bus/nscsi/devices.cpp12
-rw-r--r--src/devices/bus/nscsi/devices.h1
-rw-r--r--src/devices/bus/odyssey2/homecomp.cpp2
-rw-r--r--src/devices/bus/odyssey2/rom.cpp2
-rw-r--r--src/devices/bus/oricext/jasmin.cpp6
-rw-r--r--src/devices/bus/pofo/hpc104.cpp2
-rw-r--r--src/devices/bus/qbus/dsd4432.cpp255
-rw-r--r--src/devices/bus/qbus/dsd4432.h46
-rw-r--r--src/devices/bus/qbus/qbus.cpp2
-rw-r--r--src/devices/bus/rs232/mboardd.cpp105
-rw-r--r--src/devices/bus/rs232/mboardd.h45
-rw-r--r--src/devices/bus/rs232/rs232.cpp2
-rw-r--r--src/devices/bus/saitek_osa/expansion.cpp155
-rw-r--r--src/devices/bus/saitek_osa/expansion.h128
-rw-r--r--src/devices/bus/saitek_osa/maestro.cpp350
-rw-r--r--src/devices/bus/saitek_osa/maestro.h86
-rw-r--r--src/devices/bus/saitek_osa/maestroa.cpp196
-rw-r--r--src/devices/bus/saitek_osa/maestroa.h57
-rw-r--r--src/devices/bus/saitek_osa/modules.cpp22
-rw-r--r--src/devices/bus/saitek_osa/modules.h16
-rw-r--r--src/devices/bus/saitek_osa/sparc.cpp102
-rw-r--r--src/devices/bus/saitek_osa/sparc.h45
-rw-r--r--src/devices/bus/samcoupe/expansion/expansion.cpp8
-rw-r--r--src/devices/bus/sg1000_exp/fm_unit.h2
-rw-r--r--src/devices/bus/thomson/cd90_015.cpp120
-rw-r--r--src/devices/bus/thomson/cd90_015.h48
-rw-r--r--src/devices/bus/thomson/cd90_351.cpp495
-rw-r--r--src/devices/bus/thomson/cd90_351.h122
-rw-r--r--src/devices/bus/thomson/cd90_640.cpp91
-rw-r--r--src/devices/bus/thomson/cd90_640.h46
-rw-r--r--src/devices/bus/thomson/cq90_028.cpp76
-rw-r--r--src/devices/bus/thomson/cq90_028.h42
-rw-r--r--src/devices/bus/thomson/extension.cpp40
-rw-r--r--src/devices/bus/thomson/extension.h39
-rw-r--r--src/devices/bus/thomson/nanoreseau.cpp205
-rw-r--r--src/devices/bus/thomson/nanoreseau.h66
-rw-r--r--src/devices/bus/ti99/peb/hfdc.cpp30
-rw-r--r--src/devices/bus/ti99/peb/hfdc.h6
-rw-r--r--src/devices/bus/vsmile/keyboard.cpp569
-rw-r--r--src/devices/bus/vsmile/keyboard.h143
-rw-r--r--src/devices/bus/vsmile/mat.h3
-rw-r--r--src/devices/bus/vsmile/pad.h3
-rw-r--r--src/devices/bus/vsmile/vsmile_ctrl.cpp4
-rw-r--r--src/devices/bus/vsmile/vsmile_ctrl.h1
-rw-r--r--src/devices/bus/vtech/ioexp/ioexp.cpp73
-rw-r--r--src/devices/bus/vtech/ioexp/ioexp.h39
-rw-r--r--src/devices/bus/vtech/ioexp/joystick.cpp23
-rw-r--r--src/devices/bus/vtech/ioexp/joystick.h7
-rw-r--r--src/devices/bus/vtech/ioexp/lpen.cpp63
-rw-r--r--src/devices/bus/vtech/ioexp/lpen.h43
-rw-r--r--src/devices/bus/vtech/ioexp/printer.cpp30
-rw-r--r--src/devices/bus/vtech/ioexp/printer.h13
-rw-r--r--src/devices/bus/vtech/memexp/carts.cpp2
-rw-r--r--src/devices/bus/vtech/memexp/floppy.cpp66
-rw-r--r--src/devices/bus/vtech/memexp/floppy.h15
-rw-r--r--src/devices/bus/vtech/memexp/memexp.cpp127
-rw-r--r--src/devices/bus/vtech/memexp/memexp.h52
-rw-r--r--src/devices/bus/vtech/memexp/memory.cpp111
-rw-r--r--src/devices/bus/vtech/memexp/memory.h32
-rw-r--r--src/devices/bus/vtech/memexp/rs232.cpp46
-rw-r--r--src/devices/bus/vtech/memexp/rs232.h12
-rw-r--r--src/devices/bus/vtech/memexp/rtty.cpp32
-rw-r--r--src/devices/bus/vtech/memexp/rtty.h14
-rw-r--r--src/devices/bus/vtech/memexp/sdloader.cpp180
-rw-r--r--src/devices/bus/vtech/memexp/sdloader.h60
-rw-r--r--src/devices/bus/vtech/memexp/wordpro.cpp25
-rw-r--r--src/devices/bus/vtech/memexp/wordpro.h5
-rw-r--r--src/devices/cpu/alto2/alto2cpu.cpp12
-rw-r--r--src/devices/cpu/am29000/am29ops.h2
-rw-r--r--src/devices/cpu/arm/arm.cpp9
-rw-r--r--src/devices/cpu/arm7/arm7ops.cpp2
-rw-r--r--src/devices/cpu/drcbec.cpp14
-rw-r--r--src/devices/cpu/dsp56000/dsp56000d.cpp4
-rw-r--r--src/devices/cpu/dspp/dspp.cpp2
-rw-r--r--src/devices/cpu/h8/h83042.cpp263
-rw-r--r--src/devices/cpu/h8/h83042.h95
-rw-r--r--src/devices/cpu/i86/i286.cpp2
-rw-r--r--src/devices/cpu/m37710/m37710.cpp26
-rw-r--r--src/devices/cpu/m37710/m37710.h10
-rw-r--r--src/devices/cpu/m6502/m5074x.cpp31
-rw-r--r--src/devices/cpu/m6502/m5074x.h3
-rw-r--r--src/devices/cpu/m6800/6800dasm.cpp12
-rw-r--r--src/devices/cpu/m6800/6800dasm.h10
-rw-r--r--src/devices/cpu/m6800/6800ops.hxx24
-rw-r--r--src/devices/cpu/m6800/m6800.cpp130
-rw-r--r--src/devices/cpu/m6800/m6800.h10
-rw-r--r--src/devices/cpu/m6800/m6801.cpp398
-rw-r--r--src/devices/cpu/m6800/m6801.h63
-rw-r--r--src/devices/cpu/m68000/m68000.h4
-rw-r--r--src/devices/cpu/m68000/m68kfpu.cpp242
-rw-r--r--src/devices/cpu/m68hc16/cpu16dasm.cpp1408
-rw-r--r--src/devices/cpu/m68hc16/cpu16dasm.h59
-rw-r--r--src/devices/cpu/m88000/m88000.cpp4
-rw-r--r--src/devices/cpu/mips/mips3drc.cpp12
-rw-r--r--src/devices/cpu/mips/r4000.cpp4
-rw-r--r--src/devices/cpu/mn1880/mn1880.cpp2333
-rw-r--r--src/devices/cpu/mn1880/mn1880.h179
-rw-r--r--src/devices/cpu/mn1880/mn1880d.cpp46
-rw-r--r--src/devices/cpu/ns32000/ns32000.cpp4447
-rw-r--r--src/devices/cpu/ns32000/ns32000.h49
-rw-r--r--src/devices/cpu/ns32000/ns32000dasm.cpp6
-rw-r--r--src/devices/cpu/ns32000/slave.h18
-rw-r--r--src/devices/cpu/pdp8/hd6120.cpp1371
-rw-r--r--src/devices/cpu/pdp8/hd6120.h217
-rw-r--r--src/devices/cpu/pdp8/pdp8.cpp24
-rw-r--r--src/devices/cpu/pdp8/pdp8.h4
-rw-r--r--src/devices/cpu/pdp8/pdp8dasm.cpp1008
-rw-r--r--src/devices/cpu/pdp8/pdp8dasm.h38
-rw-r--r--src/devices/cpu/pps41/mm75op.cpp2
-rw-r--r--src/devices/cpu/psx/gte.cpp4
-rw-r--r--src/devices/cpu/romp/romp.cpp2
-rw-r--r--src/devices/cpu/rx01/rx01.cpp170
-rw-r--r--src/devices/cpu/rx01/rx01.h24
-rw-r--r--src/devices/cpu/rx01/rx01dasm.cpp2
-rw-r--r--src/devices/cpu/score/score.cpp18
-rw-r--r--src/devices/cpu/score/score.h4
-rw-r--r--src/devices/cpu/score/scoredsm.cpp7
-rw-r--r--src/devices/cpu/sharc/sharc.cpp53
-rw-r--r--src/devices/cpu/sharc/sharc.h5
-rw-r--r--src/devices/cpu/sharc/sharcdma.hxx140
-rw-r--r--src/devices/cpu/tms32031/32031ops.hxx16
-rw-r--r--src/devices/cpu/tms34010/34010ops.hxx6
-rw-r--r--src/devices/cpu/ucom4/ucom4d.cpp21
-rw-r--r--src/devices/cpu/ucom4/ucom4d.h7
-rw-r--r--src/devices/cpu/uml.cpp9
-rw-r--r--src/devices/cpu/unsp/unsp_fxxx.cpp4
-rw-r--r--src/devices/cpu/z80/kp69.cpp6
-rw-r--r--src/devices/imagedev/floppy.cpp320
-rw-r--r--src/devices/imagedev/floppy.h66
-rw-r--r--src/devices/imagedev/midiin.cpp378
-rw-r--r--src/devices/imagedev/midiin.h109
-rw-r--r--src/devices/machine/aakart.cpp209
-rw-r--r--src/devices/machine/aakart.h81
-rw-r--r--src/devices/machine/am79c90.cpp2
-rw-r--r--src/devices/machine/at28c64b.cpp279
-rw-r--r--src/devices/machine/at28c64b.h80
-rw-r--r--src/devices/machine/atmel_arm_aic.cpp4
-rw-r--r--src/devices/machine/ch376.cpp536
-rw-r--r--src/devices/machine/ch376.h81
-rw-r--r--src/devices/machine/chessmachine.cpp4
-rw-r--r--src/devices/machine/chessmachine.h4
-rw-r--r--src/devices/machine/dc7085.cpp519
-rw-r--r--src/devices/machine/dc7085.h195
-rw-r--r--src/devices/machine/dp83932c.cpp2
-rw-r--r--src/devices/machine/edlc.cpp2
-rw-r--r--src/devices/machine/generalplus_gpl16250soc.cpp4
-rw-r--r--src/devices/machine/hd63450.cpp46
-rw-r--r--src/devices/machine/hd63450.h11
-rw-r--r--src/devices/machine/hdc92x4.cpp70
-rw-r--r--src/devices/machine/hdc92x4.h3
-rw-r--r--src/devices/machine/i82586.cpp93
-rw-r--r--src/devices/machine/input_merger.cpp28
-rw-r--r--src/devices/machine/input_merger.h13
-rw-r--r--src/devices/machine/iwm.cpp14
-rw-r--r--src/devices/machine/keyboard.cpp4
-rw-r--r--src/devices/machine/mc6843.cpp1487
-rw-r--r--src/devices/machine/mc6843.h230
-rw-r--r--src/devices/machine/mc68681.cpp22
-rw-r--r--src/devices/machine/ncr5380.cpp420
-rw-r--r--src/devices/machine/ncr5380.h70
-rw-r--r--src/devices/machine/netlist.cpp3
-rw-r--r--src/devices/machine/ns32082.cpp492
-rw-r--r--src/devices/machine/ns32082.h65
-rw-r--r--src/devices/machine/ns32202.cpp26
-rw-r--r--src/devices/machine/ns32202.h12
-rw-r--r--src/devices/machine/ram.cpp16
-rw-r--r--src/devices/machine/rtc65271.cpp17
-rw-r--r--src/devices/machine/rtc65271.h2
-rw-r--r--src/devices/machine/sensorboard.cpp4
-rw-r--r--src/devices/machine/smartboard.cpp (renamed from src/mame/machine/smartboard.cpp)146
-rw-r--r--src/devices/machine/smartboard.h63
-rw-r--r--src/devices/machine/smartmed.cpp109
-rw-r--r--src/devices/machine/spg2xx_io.cpp331
-rw-r--r--src/devices/machine/spg2xx_io.h44
-rw-r--r--src/devices/machine/swim1.cpp11
-rw-r--r--src/devices/machine/swim2.cpp30
-rw-r--r--src/devices/machine/swim3.cpp2
-rw-r--r--src/devices/machine/wd1010.cpp9
-rw-r--r--src/devices/machine/wd1010.h8
-rw-r--r--src/devices/machine/wd_fdc.cpp10
-rw-r--r--src/devices/machine/z80pio.cpp5
-rw-r--r--src/devices/machine/z80scc.cpp7
-rw-r--r--src/devices/sound/ay8910.cpp2
-rw-r--r--src/devices/sound/bbd.cpp165
-rw-r--r--src/devices/sound/bbd.h93
-rw-r--r--src/devices/sound/c140.cpp21
-rw-r--r--src/devices/sound/c140.h2
-rw-r--r--src/devices/sound/c6280.cpp4
-rw-r--r--src/devices/sound/es5503.cpp2
-rw-r--r--src/devices/sound/mixer.cpp30
-rw-r--r--src/devices/sound/mixer.h27
-rw-r--r--src/devices/sound/spkrdev.cpp10
-rw-r--r--src/devices/sound/swp30.cpp6
-rw-r--r--src/devices/sound/votrax.cpp1
-rw-r--r--src/devices/sound/y8950.cpp309
-rw-r--r--src/devices/sound/y8950.h81
-rw-r--r--src/devices/sound/ym2151.cpp244
-rw-r--r--src/devices/sound/ym2151.h85
-rw-r--r--src/devices/sound/ym2154.cpp319
-rw-r--r--src/devices/sound/ym2154.h99
-rw-r--r--src/devices/sound/ym2203.cpp195
-rw-r--r--src/devices/sound/ym2203.h59
-rw-r--r--src/devices/sound/ym2413.cpp253
-rw-r--r--src/devices/sound/ym2413.h98
-rw-r--r--src/devices/sound/ym2608.cpp414
-rw-r--r--src/devices/sound/ym2608.h71
-rw-r--r--src/devices/sound/ym2610.cpp317
-rw-r--r--src/devices/sound/ym2610.h80
-rw-r--r--src/devices/sound/ym2612.cpp349
-rw-r--r--src/devices/sound/ym2612.h90
-rw-r--r--src/devices/sound/ym3526.cpp153
-rw-r--r--src/devices/sound/ym3526.h53
-rw-r--r--src/devices/sound/ym3812.cpp151
-rw-r--r--src/devices/sound/ym3812.h53
-rw-r--r--src/devices/sound/ymadpcm.h371
-rw-r--r--src/devices/sound/ymf262.cpp138
-rw-r--r--src/devices/sound/ymf262.h48
-rw-r--r--src/devices/sound/ymf278b.cpp945
-rw-r--r--src/devices/sound/ymf278b.h134
-rw-r--r--src/devices/sound/ymfm.cpp3276
-rw-r--r--src/devices/sound/ymfm.h1415
-rw-r--r--src/devices/sound/ymfm_mame.h495
-rw-r--r--src/devices/sound/ymopl.cpp373
-rw-r--r--src/devices/sound/ymopl.h208
-rw-r--r--src/devices/sound/ymopm.cpp81
-rw-r--r--src/devices/sound/ymopm.h56
-rw-r--r--src/devices/sound/ymopn.cpp300
-rw-r--r--src/devices/sound/ymopn.h196
-rw-r--r--src/devices/sound/ymopq.cpp38
-rw-r--r--src/devices/sound/ymopq.h36
-rw-r--r--src/devices/sound/ymopz.cpp22
-rw-r--r--src/devices/sound/ymopz.h29
-rw-r--r--src/devices/video/315_5124.cpp39
-rw-r--r--src/devices/video/hd61830.cpp2
-rw-r--r--src/devices/video/pc_vga.cpp6
-rw-r--r--src/devices/video/pwm.cpp128
-rw-r--r--src/devices/video/pwm.h23
-rw-r--r--src/devices/video/t6963c.cpp12
-rw-r--r--src/devices/video/upd7220.cpp299
-rw-r--r--src/devices/video/upd7220.h13
-rw-r--r--src/devices/video/vooddefs.ipp20
-rw-r--r--src/devices/video/voodoo.cpp4
-rw-r--r--src/emu/debug/dvdisasm.cpp8
-rw-r--r--src/emu/dinetwork.cpp8
-rw-r--r--src/emu/dinetwork.h2
-rw-r--r--src/emu/emumem.cpp4
-rw-r--r--src/emu/emumem.h3
-rw-r--r--src/emu/emumem_hedr.ipp54
-rw-r--r--src/emu/emumem_hedw.ipp48
-rw-r--r--src/emu/emumem_mview.cpp10
-rw-r--r--src/emu/emuopts.cpp1
-rw-r--r--src/emu/emuopts.h2
-rw-r--r--src/emu/layout/smartboard.lay453
-rw-r--r--src/emu/machine.cpp67
-rw-r--r--src/emu/machine.h31
-rw-r--r--src/emu/render.h2
-rw-r--r--src/emu/rendlay.cpp4
-rw-r--r--src/emu/screen.h2
-rw-r--r--src/emu/sound.h32
-rw-r--r--src/emu/validity.cpp8
-rw-r--r--src/emu/video.cpp12
-rw-r--r--src/emu/xtal.cpp2
-rw-r--r--src/frontend/mame/clifront.cpp2
-rw-r--r--src/frontend/mame/luaengine.cpp21
-rw-r--r--src/frontend/mame/media_ident.cpp10
-rw-r--r--src/frontend/mame/ui/confswitch.cpp2
-rw-r--r--src/frontend/mame/ui/filecreate.cpp11
-rw-r--r--src/frontend/mame/ui/filecreate.h9
-rw-r--r--src/frontend/mame/ui/floppycntrl.cpp36
-rw-r--r--src/frontend/mame/ui/floppycntrl.h1
-rw-r--r--src/frontend/mame/ui/imgcntrl.cpp7
-rw-r--r--src/frontend/mame/ui/inputmap.cpp10
-rw-r--r--src/frontend/mame/ui/miscmenu.cpp55
-rw-r--r--src/frontend/mame/ui/selmenu.cpp2
-rw-r--r--src/frontend/mame/ui/swlist.cpp6
-rw-r--r--src/lib/formats/all.cpp31
-rw-r--r--src/lib/formats/all.h2
-rw-r--r--src/lib/formats/ap_dsk35.cpp6
-rw-r--r--src/lib/formats/esq8_dsk.cpp40
-rw-r--r--src/lib/formats/flopimg.cpp28
-rw-r--r--src/lib/formats/flopimg.h121
-rw-r--r--src/lib/formats/fs_oric_jasmin.cpp623
-rw-r--r--src/lib/formats/fs_oric_jasmin.h124
-rw-r--r--src/lib/formats/fs_prodos.cpp449
-rw-r--r--src/lib/formats/fs_prodos.h94
-rw-r--r--src/lib/formats/fs_unformatted.cpp73
-rw-r--r--src/lib/formats/fs_unformatted.h23
-rw-r--r--src/lib/formats/fs_vtech.cpp366
-rw-r--r--src/lib/formats/fs_vtech.h96
-rw-r--r--src/lib/formats/fsblk_vec.cpp39
-rw-r--r--src/lib/formats/fsblk_vec.h33
-rw-r--r--src/lib/formats/fsmgr.cpp436
-rw-r--r--src/lib/formats/fsmgr.h444
-rw-r--r--src/lib/formats/ipf_dsk.cpp79
-rw-r--r--src/lib/formats/ipf_dsk.h128
-rw-r--r--src/lib/formats/kaypro_dsk.cpp4
-rw-r--r--src/lib/formats/mfi_dsk.cpp9
-rw-r--r--src/lib/formats/oric_dsk.cpp98
-rw-r--r--src/lib/formats/oric_dsk.h19
-rw-r--r--src/lib/formats/thom_dsk.cpp462
-rw-r--r--src/lib/formats/thom_dsk.h38
-rw-r--r--src/lib/formats/vt_dsk.cpp396
-rw-r--r--src/lib/formats/vt_dsk.h58
-rw-r--r--src/lib/formats/wd177x_dsk.cpp18
-rw-r--r--src/lib/util/cdrom.cpp44
-rw-r--r--src/lib/util/msdib.cpp4
-rw-r--r--src/lib/util/timeconv.cpp17
-rw-r--r--src/lib/util/timeconv.h24
-rw-r--r--src/mame/arcade.flt8
-rw-r--r--src/mame/audio/acan.cpp297
-rw-r--r--src/mame/audio/acan.h68
-rw-r--r--src/mame/audio/atarijsa.h2
-rw-r--r--src/mame/audio/dragrace.cpp42
-rw-r--r--src/mame/audio/gottlieb.cpp27
-rw-r--r--src/mame/audio/gottlieb.h1
-rw-r--r--src/mame/audio/laserbat.cpp6
-rw-r--r--src/mame/audio/leland.h2
-rw-r--r--src/mame/audio/nichisnd.h2
-rw-r--r--src/mame/audio/nitedrvr.cpp44
-rw-r--r--src/mame/audio/nl_segas16b.cpp12
-rw-r--r--src/mame/audio/pinsnd88.h2
-rw-r--r--src/mame/audio/s11c_bg.h2
-rw-r--r--src/mame/audio/segam1audio.h2
-rw-r--r--src/mame/audio/sprint2.cpp56
-rw-r--r--src/mame/audio/t5182.h2
-rw-r--r--src/mame/audio/williams.cpp2
-rw-r--r--src/mame/audio/williams.h2
-rw-r--r--src/mame/audio/wpcsnd.h2
-rw-r--r--src/mame/drivers/1942.cpp10
-rw-r--r--src/mame/drivers/1943.cpp8
-rw-r--r--src/mame/drivers/2mindril.cpp4
-rw-r--r--src/mame/drivers/8080bw.cpp2
-rw-r--r--src/mame/drivers/88games.cpp2
-rw-r--r--src/mame/drivers/aa310.cpp18
-rw-r--r--src/mame/drivers/aci_ggm.cpp43
-rw-r--r--src/mame/drivers/actfancr.cpp4
-rw-r--r--src/mame/drivers/aerofgt.cpp72
-rw-r--r--src/mame/drivers/airbustr.cpp2
-rw-r--r--src/mame/drivers/airraid.cpp2
-rw-r--r--src/mame/drivers/ajax.cpp2
-rw-r--r--src/mame/drivers/alg.cpp22
-rw-r--r--src/mame/drivers/aliens.cpp36
-rw-r--r--src/mame/drivers/alpha68k_n.cpp8
-rw-r--r--src/mame/drivers/alphatro.cpp335
-rw-r--r--src/mame/drivers/amaticmg.cpp2
-rw-r--r--src/mame/drivers/amstr_pc.cpp12
-rw-r--r--src/mame/drivers/anes.cpp2
-rw-r--r--src/mame/drivers/angelkds.cpp2
-rw-r--r--src/mame/drivers/apple2.cpp8
-rw-r--r--src/mame/drivers/apple2e.cpp14
-rw-r--r--src/mame/drivers/apple2gs.cpp70
-rw-r--r--src/mame/drivers/apple3.cpp4
-rw-r--r--src/mame/drivers/aquarium.cpp2
-rw-r--r--src/mame/drivers/aquarius.cpp46
-rw-r--r--src/mame/drivers/argus.cpp2
-rw-r--r--src/mame/drivers/aristmk5.cpp2958
-rw-r--r--src/mame/drivers/armedf.cpp3
-rw-r--r--src/mame/drivers/ashnojoe.cpp2
-rw-r--r--src/mame/drivers/asterix.cpp4
-rw-r--r--src/mame/drivers/astrocde.cpp2
-rw-r--r--src/mame/drivers/asuka.cpp61
-rw-r--r--src/mame/drivers/at.cpp4
-rw-r--r--src/mame/drivers/atari_s1.cpp12
-rw-r--r--src/mame/drivers/atari_s2.cpp25
-rw-r--r--src/mame/drivers/atarisy1.cpp2
-rw-r--r--src/mame/drivers/atetris.cpp19
-rw-r--r--src/mame/drivers/ave_arb.cpp2
-rw-r--r--src/mame/drivers/basf7100.cpp388
-rw-r--r--src/mame/drivers/basssta.cpp31
-rw-r--r--src/mame/drivers/battlane.cpp2
-rw-r--r--src/mame/drivers/battlera.cpp2
-rw-r--r--src/mame/drivers/battlnts.cpp2
-rw-r--r--src/mame/drivers/bbusters.cpp2
-rw-r--r--src/mame/drivers/bebox.cpp2
-rw-r--r--src/mame/drivers/bfcobra.cpp2
-rw-r--r--src/mame/drivers/bfm_sc2.cpp2
-rw-r--r--src/mame/drivers/bigkarnk_ms.cpp2
-rw-r--r--src/mame/drivers/bingo.cpp15
-rw-r--r--src/mame/drivers/bingoc.cpp93
-rw-r--r--src/mame/drivers/bingowav.cpp2
-rw-r--r--src/mame/drivers/bionicc.cpp12
-rw-r--r--src/mame/drivers/bladestl.cpp2
-rw-r--r--src/mame/drivers/blktiger.cpp7
-rw-r--r--src/mame/drivers/blktiger_ms.cpp2
-rw-r--r--src/mame/drivers/blockhl.cpp2
-rw-r--r--src/mame/drivers/blockout.cpp2
-rw-r--r--src/mame/drivers/bloodbro_ms.cpp2
-rw-r--r--src/mame/drivers/bmcbowl.cpp2
-rw-r--r--src/mame/drivers/bmcpokr.cpp2
-rw-r--r--src/mame/drivers/bml3.cpp60
-rw-r--r--src/mame/drivers/boogwing.cpp2
-rw-r--r--src/mame/drivers/brkthru.cpp4
-rw-r--r--src/mame/drivers/bublbobl.cpp40
-rw-r--r--src/mame/drivers/bw12.cpp8
-rw-r--r--src/mame/drivers/cabal.cpp2
-rw-r--r--src/mame/drivers/cabaret.cpp2
-rw-r--r--src/mame/drivers/calomega.cpp3809
-rw-r--r--src/mame/drivers/canon_s80.cpp305
-rw-r--r--src/mame/drivers/capbowl.cpp2
-rw-r--r--src/mame/drivers/capr1.cpp2
-rw-r--r--src/mame/drivers/cave.cpp4
-rw-r--r--src/mame/drivers/cbasebal.cpp2
-rw-r--r--src/mame/drivers/cbuster.cpp4
-rw-r--r--src/mame/drivers/cc40.cpp178
-rw-r--r--src/mame/drivers/cclimber.cpp93
-rw-r--r--src/mame/drivers/cgang.cpp2
-rw-r--r--src/mame/drivers/chanbara.cpp2
-rw-r--r--src/mame/drivers/changyu.cpp2
-rw-r--r--src/mame/drivers/chessmate.cpp12
-rw-r--r--src/mame/drivers/chessmst.cpp472
-rw-r--r--src/mame/drivers/chessmstdm.cpp354
-rw-r--r--src/mame/drivers/chexx.cpp61
-rw-r--r--src/mame/drivers/chinagat.cpp4
-rw-r--r--src/mame/drivers/chinsan.cpp2
-rw-r--r--src/mame/drivers/chqflag.cpp2
-rw-r--r--src/mame/drivers/cischeat.cpp2
-rw-r--r--src/mame/drivers/citycon.cpp2
-rw-r--r--src/mame/drivers/cninja.cpp4
-rw-r--r--src/mame/drivers/coco12.cpp1
-rw-r--r--src/mame/drivers/coco3.cpp39
-rw-r--r--src/mame/drivers/cointek.cpp2
-rw-r--r--src/mame/drivers/coleco.cpp10
-rw-r--r--src/mame/drivers/combatsc.cpp492
-rw-r--r--src/mame/drivers/commando.cpp9
-rw-r--r--src/mame/drivers/compgolf.cpp2
-rw-r--r--src/mame/drivers/contra.cpp2
-rw-r--r--src/mame/drivers/cop01.cpp32
-rw-r--r--src/mame/drivers/cps1.cpp2
-rw-r--r--src/mame/drivers/cps1bl_5205.cpp2
-rw-r--r--src/mame/drivers/cps2.cpp10
-rw-r--r--src/mame/drivers/cpzodiac.cpp6
-rw-r--r--src/mame/drivers/crei680.cpp339
-rw-r--r--src/mame/drivers/crimfght.cpp2
-rw-r--r--src/mame/drivers/crospang.cpp2
-rw-r--r--src/mame/drivers/crshrace.cpp2
-rw-r--r--src/mame/drivers/cxg_sphinx40.cpp16
-rw-r--r--src/mame/drivers/cybertnk.cpp2
-rw-r--r--src/mame/drivers/cyclemb.cpp481
-rw-r--r--src/mame/drivers/d9final.cpp2
-rw-r--r--src/mame/drivers/dacholer.cpp3
-rw-r--r--src/mame/drivers/dai3wksi.cpp318
-rw-r--r--src/mame/drivers/dangbar.cpp128
-rw-r--r--src/mame/drivers/darius.cpp2
-rw-r--r--src/mame/drivers/darkseal.cpp4
-rw-r--r--src/mame/drivers/dassault.cpp4
-rw-r--r--src/mame/drivers/dblewing.cpp2
-rw-r--r--src/mame/drivers/dbz.cpp2
-rw-r--r--src/mame/drivers/dcon.cpp4
-rw-r--r--src/mame/drivers/ddealer.cpp2
-rw-r--r--src/mame/drivers/ddenlovr.cpp2
-rw-r--r--src/mame/drivers/ddragon.cpp4
-rw-r--r--src/mame/drivers/ddragon3.cpp2
-rw-r--r--src/mame/drivers/ddribble.cpp260
-rw-r--r--src/mame/drivers/de_2.cpp2
-rw-r--r--src/mame/drivers/de_3.cpp31
-rw-r--r--src/mame/drivers/deadang.cpp2
-rw-r--r--src/mame/drivers/dec0.cpp4
-rw-r--r--src/mame/drivers/dec8.cpp5
-rw-r--r--src/mame/drivers/decmate2.cpp1007
-rw-r--r--src/mame/drivers/deco32.cpp10
-rw-r--r--src/mame/drivers/decstation.cpp760
-rw-r--r--src/mame/drivers/deniam.cpp2
-rw-r--r--src/mame/drivers/dfruit.cpp2
-rw-r--r--src/mame/drivers/diamondking.cpp106
-rw-r--r--src/mame/drivers/dietgo.cpp2
-rw-r--r--src/mame/drivers/discoboy.cpp2
-rw-r--r--src/mame/drivers/djboy.cpp2
-rw-r--r--src/mame/drivers/dooyong.cpp4
-rw-r--r--src/mame/drivers/dpb7000.cpp54
-rw-r--r--src/mame/drivers/dragon.cpp56
-rw-r--r--src/mame/drivers/dragrace.cpp120
-rw-r--r--src/mame/drivers/drumsta.cpp9
-rw-r--r--src/mame/drivers/dunhuang.cpp2
-rw-r--r--src/mame/drivers/dynadice.cpp2
-rw-r--r--src/mame/drivers/dynax.cpp5
-rw-r--r--src/mame/drivers/dynduke.cpp2
-rw-r--r--src/mame/drivers/elzet80.cpp181
-rw-r--r--src/mame/drivers/enmirage.cpp436
-rw-r--r--src/mame/drivers/ertictac.cpp78
-rw-r--r--src/mame/drivers/esd16.cpp2
-rw-r--r--src/mame/drivers/exerion.cpp352
-rw-r--r--src/mame/drivers/exidy.cpp54
-rw-r--r--src/mame/drivers/exprraid.cpp4
-rw-r--r--src/mame/drivers/exzisus.cpp2
-rw-r--r--src/mame/drivers/f-32.cpp4
-rw-r--r--src/mame/drivers/f1gp.cpp2
-rw-r--r--src/mame/drivers/fantland.cpp4
-rw-r--r--src/mame/drivers/fb01.cpp6
-rw-r--r--src/mame/drivers/fcrash.cpp4
-rw-r--r--src/mame/drivers/ffantasy_ms.cpp2
-rw-r--r--src/mame/drivers/fidel_cc1.cpp2
-rw-r--r--src/mame/drivers/fidel_desdis.cpp4
-rw-r--r--src/mame/drivers/fidel_eag68k.cpp1
-rw-r--r--src/mame/drivers/fidel_elite.cpp10
-rw-r--r--src/mame/drivers/fidel_excel.cpp2
-rw-r--r--src/mame/drivers/fidel_phantom.cpp4
-rw-r--r--src/mame/drivers/fidel_sc6.cpp2
-rw-r--r--src/mame/drivers/fidel_sc8.cpp4
-rw-r--r--src/mame/drivers/fidel_sc9.cpp16
-rw-r--r--src/mame/drivers/finalizr.cpp120
-rw-r--r--src/mame/drivers/firebeat.cpp43
-rw-r--r--src/mame/drivers/firetrap.cpp2
-rw-r--r--src/mame/drivers/flkatck.cpp4
-rw-r--r--src/mame/drivers/fm7.cpp2
-rw-r--r--src/mame/drivers/fmtowns.cpp36
-rw-r--r--src/mame/drivers/fresh.cpp2
-rw-r--r--src/mame/drivers/fromanc2.cpp2
-rw-r--r--src/mame/drivers/fromance.cpp2
-rw-r--r--src/mame/drivers/funkyjet.cpp65
-rw-r--r--src/mame/drivers/fuukifg2.cpp4
-rw-r--r--src/mame/drivers/fuukifg3.cpp91
-rw-r--r--src/mame/drivers/fwheel.cpp211
-rw-r--r--src/mame/drivers/gaelco.cpp2
-rw-r--r--src/mame/drivers/gaiden.cpp4
-rw-r--r--src/mame/drivers/galaxian.cpp1197
-rw-r--r--src/mame/drivers/galaxian_rockclim.cpp293
-rw-r--r--src/mame/drivers/galaxold.cpp314
-rw-r--r--src/mame/drivers/galivan.cpp4
-rw-r--r--src/mame/drivers/galpanic_ms.cpp2
-rw-r--r--src/mame/drivers/galspnbl.cpp2
-rw-r--r--src/mame/drivers/gameplan.cpp2
-rw-r--r--src/mame/drivers/gauntlet.cpp2
-rw-r--r--src/mame/drivers/ginganin.cpp2
-rw-r--r--src/mame/drivers/gladiatr.cpp2
-rw-r--r--src/mame/drivers/gluck2.cpp2
-rw-r--r--src/mame/drivers/gng.cpp5
-rw-r--r--src/mame/drivers/goal92.cpp2
-rw-r--r--src/mame/drivers/goindol.cpp2
-rw-r--r--src/mame/drivers/gokidetor.cpp2
-rw-r--r--src/mame/drivers/goldstar.cpp3
-rw-r--r--src/mame/drivers/goodejan.cpp2
-rw-r--r--src/mame/drivers/goori.cpp2
-rw-r--r--src/mame/drivers/gotcha.cpp2
-rw-r--r--src/mame/drivers/gradius3.cpp2
-rw-r--r--src/mame/drivers/gsspade.cpp2
-rw-r--r--src/mame/drivers/gstriker.cpp2
-rw-r--r--src/mame/drivers/gticlub.cpp606
-rw-r--r--src/mame/drivers/gundealr.cpp2
-rw-r--r--src/mame/drivers/gunpey.cpp577
-rw-r--r--src/mame/drivers/gunsmoke.cpp9
-rw-r--r--src/mame/drivers/h01x.cpp223
-rw-r--r--src/mame/drivers/hcastle.cpp2
-rw-r--r--src/mame/drivers/heromem.cpp2
-rw-r--r--src/mame/drivers/hh_cops1.cpp168
-rw-r--r--src/mame/drivers/hh_hmcs40.cpp3
-rw-r--r--src/mame/drivers/hh_pic16.cpp5
-rw-r--r--src/mame/drivers/hh_pps41.cpp4
-rw-r--r--src/mame/drivers/hh_sm510.cpp69
-rw-r--r--src/mame/drivers/hh_tms1k.cpp42
-rw-r--r--src/mame/drivers/hh_ucom4.cpp2
-rw-r--r--src/mame/drivers/himesiki.cpp2
-rw-r--r--src/mame/drivers/hnayayoi.cpp10
-rw-r--r--src/mame/drivers/homerun.cpp2
-rw-r--r--src/mame/drivers/hornet.cpp1285
-rw-r--r--src/mame/drivers/hp80.cpp2
-rw-r--r--src/mame/drivers/hp9825.cpp2
-rw-r--r--src/mame/drivers/hp9845.cpp2
-rw-r--r--src/mame/drivers/hshavoc.cpp2
-rw-r--r--src/mame/drivers/hvyunit.cpp2
-rw-r--r--src/mame/drivers/hyprduel.cpp4
-rw-r--r--src/mame/drivers/ibmpcjr.cpp2
-rw-r--r--src/mame/drivers/ichiban.cpp2
-rw-r--r--src/mame/drivers/igs009.cpp2
-rw-r--r--src/mame/drivers/igs011.cpp3
-rw-r--r--src/mame/drivers/igs017.cpp2
-rw-r--r--src/mame/drivers/igspoker.cpp2
-rw-r--r--src/mame/drivers/inder.cpp43
-rw-r--r--src/mame/drivers/indigo.cpp7
-rw-r--r--src/mame/drivers/informer_213.cpp7
-rw-r--r--src/mame/drivers/intellec8.cpp83
-rw-r--r--src/mame/drivers/intellect02.cpp2
-rw-r--r--src/mame/drivers/inufuku.cpp417
-rw-r--r--src/mame/drivers/iqblock.cpp2
-rw-r--r--src/mame/drivers/ironhors.cpp206
-rw-r--r--src/mame/drivers/itech32.cpp466
-rw-r--r--src/mame/drivers/itech8.cpp5
-rw-r--r--src/mame/drivers/jack.cpp13
-rw-r--r--src/mame/drivers/jackal.cpp285
-rw-r--r--src/mame/drivers/jackie.cpp2
-rw-r--r--src/mame/drivers/jackpot.cpp2
-rw-r--r--src/mame/drivers/joctronic.cpp24
-rw-r--r--src/mame/drivers/joystand.cpp2
-rw-r--r--src/mame/drivers/jpmimpctsw.cpp208
-rw-r--r--src/mame/drivers/junior80.cpp3
-rw-r--r--src/mame/drivers/karnov.cpp5
-rw-r--r--src/mame/drivers/kaypro.cpp23
-rw-r--r--src/mame/drivers/kikikai.cpp38
-rw-r--r--src/mame/drivers/kingdrby.cpp2
-rw-r--r--src/mame/drivers/kminus.cpp337
-rw-r--r--src/mame/drivers/koftball.cpp2
-rw-r--r--src/mame/drivers/konamigv.cpp164
-rw-r--r--src/mame/drivers/korgds8.cpp2
-rw-r--r--src/mame/drivers/korgz3.cpp2
-rw-r--r--src/mame/drivers/ksys573.cpp229
-rw-r--r--src/mame/drivers/labyrunr.cpp10
-rw-r--r--src/mame/drivers/ladybug.cpp439
-rw-r--r--src/mame/drivers/laserbat.cpp24
-rw-r--r--src/mame/drivers/lastbank.cpp2
-rw-r--r--src/mame/drivers/lastduel.cpp2
-rw-r--r--src/mame/drivers/lc80.cpp548
-rw-r--r--src/mame/drivers/leapfrog_leappad.cpp38
-rw-r--r--src/mame/drivers/leapfrog_leapster_explorer.cpp108
-rw-r--r--src/mame/drivers/leapster.cpp85
-rw-r--r--src/mame/drivers/legionna.cpp300
-rw-r--r--src/mame/drivers/lemmings.cpp2
-rw-r--r--src/mame/drivers/lkage.cpp2
-rw-r--r--src/mame/drivers/lnw80.cpp666
-rw-r--r--src/mame/drivers/lockon.cpp2
-rw-r--r--src/mame/drivers/lordgun.cpp3
-rw-r--r--src/mame/drivers/lsasquad.cpp2
-rw-r--r--src/mame/drivers/lwings.cpp2
-rw-r--r--src/mame/drivers/m107.cpp2
-rw-r--r--src/mame/drivers/m72.cpp6
-rw-r--r--src/mame/drivers/m79amb.cpp20
-rw-r--r--src/mame/drivers/m90.cpp2
-rw-r--r--src/mame/drivers/m92.cpp2
-rw-r--r--src/mame/drivers/mac.cpp52
-rw-r--r--src/mame/drivers/mac128.cpp65
-rw-r--r--src/mame/drivers/macpci.cpp22
-rw-r--r--src/mame/drivers/macprtb.cpp101
-rw-r--r--src/mame/drivers/macpwrbk030.cpp114
-rw-r--r--src/mame/drivers/macquadra700.cpp18
-rw-r--r--src/mame/drivers/madmotor.cpp4
-rw-r--r--src/mame/drivers/mainevt.cpp2
-rw-r--r--src/mame/drivers/matmania.cpp2
-rw-r--r--src/mame/drivers/max80.cpp18
-rw-r--r--src/mame/drivers/maygayv1.cpp2
-rw-r--r--src/mame/drivers/mbee.cpp477
-rw-r--r--src/mame/drivers/mc10.cpp431
-rw-r--r--src/mame/drivers/mcatadv.cpp2
-rw-r--r--src/mame/drivers/mcr68.cpp478
-rw-r--r--src/mame/drivers/mechatt.cpp2
-rw-r--r--src/mame/drivers/megasys1.cpp46
-rw-r--r--src/mame/drivers/megatech.cpp2
-rw-r--r--src/mame/drivers/mephisto_academy.cpp4
-rw-r--r--src/mame/drivers/mephisto_berlin.cpp25
-rw-r--r--src/mame/drivers/mephisto_brikett.cpp4
-rw-r--r--src/mame/drivers/mephisto_milano.cpp5
-rw-r--r--src/mame/drivers/mephisto_mm2.cpp18
-rw-r--r--src/mame/drivers/mephisto_modular.cpp70
-rw-r--r--src/mame/drivers/mephisto_modular_tm.cpp16
-rw-r--r--src/mame/drivers/mephisto_mondial.cpp2
-rw-r--r--src/mame/drivers/mephisto_mondial2.cpp2
-rw-r--r--src/mame/drivers/mephisto_mondial68k.cpp2
-rw-r--r--src/mame/drivers/mephisto_montec.cpp8
-rw-r--r--src/mame/drivers/mephisto_polgar.cpp2
-rw-r--r--src/mame/drivers/mephisto_risc.cpp5
-rw-r--r--src/mame/drivers/mephisto_smondial.cpp2
-rw-r--r--src/mame/drivers/mephistp.cpp2
-rw-r--r--src/mame/drivers/merit.cpp110
-rw-r--r--src/mame/drivers/merit3xx.cpp225
-rw-r--r--src/mame/drivers/merits.cpp3
-rw-r--r--src/mame/drivers/meritum.cpp313
-rw-r--r--src/mame/drivers/mermaid.cpp26
-rw-r--r--src/mame/drivers/metlclsh.cpp6
-rw-r--r--src/mame/drivers/metro.cpp5
-rw-r--r--src/mame/drivers/mg1.cpp402
-rw-r--r--src/mame/drivers/micro3d.cpp2
-rw-r--r--src/mame/drivers/missamer.cpp563
-rw-r--r--src/mame/drivers/missb2.cpp2
-rw-r--r--src/mame/drivers/missbamby.cpp2
-rw-r--r--src/mame/drivers/mitchell.cpp149
-rw-r--r--src/mame/drivers/mlanding.cpp2
-rw-r--r--src/mame/drivers/model1.cpp134
-rw-r--r--src/mame/drivers/model2.cpp2
-rw-r--r--src/mame/drivers/momoko.cpp2
-rw-r--r--src/mame/drivers/moo.cpp2
-rw-r--r--src/mame/drivers/mosaic.cpp2
-rw-r--r--src/mame/drivers/mpu4vid.cpp2
-rw-r--r--src/mame/drivers/mugsmash.cpp2
-rw-r--r--src/mame/drivers/multi8.cpp2
-rw-r--r--src/mame/drivers/namcos1.cpp56
-rw-r--r--src/mame/drivers/namcos11.cpp23
-rw-r--r--src/mame/drivers/namcos2.cpp123
-rw-r--r--src/mame/drivers/namcos21.cpp2
-rw-r--r--src/mame/drivers/namcos21_c67.cpp2
-rw-r--r--src/mame/drivers/namcos21_de.cpp2
-rw-r--r--src/mame/drivers/namcos22.cpp156
-rw-r--r--src/mame/drivers/namcos86.cpp2
-rw-r--r--src/mame/drivers/naomi.cpp69
-rw-r--r--src/mame/drivers/nbmj8688.cpp2
-rw-r--r--src/mame/drivers/nbmj8891.cpp2
-rw-r--r--src/mame/drivers/nbmj8900.cpp2
-rw-r--r--src/mame/drivers/nbmj8991.cpp2
-rw-r--r--src/mame/drivers/nbmj9195.cpp2
-rw-r--r--src/mame/drivers/nemesis.cpp4
-rw-r--r--src/mame/drivers/neoprint.cpp2
-rw-r--r--src/mame/drivers/neptunp2.cpp89
-rw-r--r--src/mame/drivers/nes_clone.cpp22
-rw-r--r--src/mame/drivers/nes_vt369_vtunknown.cpp32
-rw-r--r--src/mame/drivers/nightgal.cpp8
-rw-r--r--src/mame/drivers/ninjakd2.cpp2
-rw-r--r--src/mame/drivers/ninjaw.cpp2
-rw-r--r--src/mame/drivers/nitedrvr.cpp44
-rw-r--r--src/mame/drivers/nmg5.cpp2
-rw-r--r--src/mame/drivers/nmk16.cpp6
-rw-r--r--src/mame/drivers/novag_cforte.cpp2
-rw-r--r--src/mame/drivers/novag_const.cpp2
-rw-r--r--src/mame/drivers/novag_savant.cpp27
-rw-r--r--src/mame/drivers/novag_sexpert.cpp3
-rw-r--r--src/mame/drivers/novag_snova.cpp9
-rw-r--r--src/mame/drivers/nwk-tr.cpp513
-rw-r--r--src/mame/drivers/odyssey2.cpp2
-rw-r--r--src/mame/drivers/ojankohs.cpp356
-rw-r--r--src/mame/drivers/olibochu.cpp2
-rw-r--r--src/mame/drivers/oneshot.cpp2
-rw-r--r--src/mame/drivers/onetwo.cpp2
-rw-r--r--src/mame/drivers/opwolf.cpp2
-rw-r--r--src/mame/drivers/othunder.cpp2
-rw-r--r--src/mame/drivers/overdriv.cpp2
-rw-r--r--src/mame/drivers/pacman.cpp113
-rw-r--r--src/mame/drivers/parodius.cpp2
-rw-r--r--src/mame/drivers/pasha2.cpp335
-rw-r--r--src/mame/drivers/pass.cpp2
-rw-r--r--src/mame/drivers/pc.cpp159
-rw-r--r--src/mame/drivers/pc88va.cpp10
-rw-r--r--src/mame/drivers/pc9801.cpp609
-rw-r--r--src/mame/drivers/pcktgal.cpp4
-rw-r--r--src/mame/drivers/pcxt.cpp45
-rw-r--r--src/mame/drivers/philipsbo.cpp271
-rw-r--r--src/mame/drivers/phoenix.cpp83
-rw-r--r--src/mame/drivers/pipedrm.cpp3
-rw-r--r--src/mame/drivers/pipeline.cpp2
-rw-r--r--src/mame/drivers/pkscram.cpp2
-rw-r--r--src/mame/drivers/plsonic4.cpp195
-rw-r--r--src/mame/drivers/pofo.cpp260
-rw-r--r--src/mame/drivers/pokechmp.cpp4
-rw-r--r--src/mame/drivers/poly880.cpp326
-rw-r--r--src/mame/drivers/popobear.cpp2
-rw-r--r--src/mame/drivers/powerins.cpp2
-rw-r--r--src/mame/drivers/ppmast93.cpp2
-rw-r--r--src/mame/drivers/prehisle.cpp2
-rw-r--r--src/mame/drivers/psikyo.cpp38
-rw-r--r--src/mame/drivers/psikyosh.cpp243
-rw-r--r--src/mame/drivers/psrockman.cpp142
-rw-r--r--src/mame/drivers/psychic5.cpp2
-rw-r--r--src/mame/drivers/puckpkmn.cpp2
-rw-r--r--src/mame/drivers/quizdna.cpp2
-rw-r--r--src/mame/drivers/quizpun2.cpp2
-rw-r--r--src/mame/drivers/qx10.cpp58
-rw-r--r--src/mame/drivers/r2dx_v33.cpp2
-rw-r--r--src/mame/drivers/radionic.cpp578
-rw-r--r--src/mame/drivers/raiden.cpp2
-rw-r--r--src/mame/drivers/raiden2.cpp46
-rw-r--r--src/mame/drivers/raiden_ms.cpp2
-rw-r--r--src/mame/drivers/rastan.cpp2
-rw-r--r--src/mame/drivers/rbisland.cpp4
-rw-r--r--src/mame/drivers/rbmk.cpp2
-rw-r--r--src/mame/drivers/realbrk.cpp2
-rw-r--r--src/mame/drivers/regence.cpp12
-rw-r--r--src/mame/drivers/relief.cpp2
-rw-r--r--src/mame/drivers/renegade.cpp2
-rw-r--r--src/mame/drivers/rfslots8085.cpp9
-rw-r--r--src/mame/drivers/rfslotsmcs48.cpp82
-rw-r--r--src/mame/drivers/rmnimbus.cpp39
-rw-r--r--src/mame/drivers/rockrage.cpp2
-rw-r--r--src/mame/drivers/rohga.cpp48
-rw-r--r--src/mame/drivers/roland_cm32p.cpp104
-rw-r--r--src/mame/drivers/roland_pr100.cpp121
-rw-r--r--src/mame/drivers/roland_s10.cpp38
-rw-r--r--src/mame/drivers/rollerg.cpp2
-rw-r--r--src/mame/drivers/rpunch.cpp2
-rw-r--r--src/mame/drivers/rx78.cpp154
-rw-r--r--src/mame/drivers/sag.cpp2
-rw-r--r--src/mame/drivers/saitek_corona.cpp27
-rw-r--r--src/mame/drivers/saitek_leonardo.cpp183
-rw-r--r--src/mame/drivers/saitek_renaissance.cpp161
-rw-r--r--src/mame/drivers/saitek_risc2500.cpp442
-rw-r--r--src/mame/drivers/saitek_schess.cpp1
-rw-r--r--src/mame/drivers/saitek_simultano.cpp7
-rw-r--r--src/mame/drivers/saitek_ssystem3.cpp1
-rw-r--r--src/mame/drivers/saitek_stratos.cpp48
-rw-r--r--src/mame/drivers/saitek_superstar.cpp7
-rw-r--r--src/mame/drivers/sandscrp.cpp2
-rw-r--r--src/mame/drivers/sangho.cpp2
-rw-r--r--src/mame/drivers/sauro.cpp2
-rw-r--r--src/mame/drivers/sbmjb.cpp2
-rw-r--r--src/mame/drivers/sbrain.cpp38
-rw-r--r--src/mame/drivers/sc2.cpp43
-rw-r--r--src/mame/drivers/schexx4gen.cpp46
-rw-r--r--src/mame/drivers/schick.cpp195
-rw-r--r--src/mame/drivers/scotrsht.cpp2
-rw-r--r--src/mame/drivers/segac2.cpp2
-rw-r--r--src/mame/drivers/segacoin.cpp2
-rw-r--r--src/mame/drivers/segahang.cpp6
-rw-r--r--src/mame/drivers/segajw.cpp2
-rw-r--r--src/mame/drivers/segam1.cpp4
-rw-r--r--src/mame/drivers/segaorun.cpp2
-rw-r--r--src/mame/drivers/segas16a.cpp22
-rw-r--r--src/mame/drivers/segas16b.cpp12
-rw-r--r--src/mame/drivers/segas18.cpp2
-rw-r--r--src/mame/drivers/segas24.cpp2
-rw-r--r--src/mame/drivers/segas32.cpp2
-rw-r--r--src/mame/drivers/segasp.cpp21
-rw-r--r--src/mame/drivers/segaufo.cpp10
-rw-r--r--src/mame/drivers/segaxbd.cpp2
-rw-r--r--src/mame/drivers/segaybd.cpp2
-rw-r--r--src/mame/drivers/sengokmj.cpp14
-rw-r--r--src/mame/drivers/seta.cpp88
-rw-r--r--src/mame/drivers/sf.cpp2
-rw-r--r--src/mame/drivers/sfkick.cpp2
-rw-r--r--src/mame/drivers/shadfrce.cpp2
-rw-r--r--src/mame/drivers/shangha3.cpp2
-rw-r--r--src/mame/drivers/shanghai.cpp2
-rw-r--r--src/mame/drivers/shangkid.cpp19
-rw-r--r--src/mame/drivers/shisen.cpp2
-rw-r--r--src/mame/drivers/shootout.cpp2
-rw-r--r--src/mame/drivers/sidearms.cpp4
-rw-r--r--src/mame/drivers/sidepckt.cpp4
-rw-r--r--src/mame/drivers/sigmab31.cpp2
-rw-r--r--src/mame/drivers/sigmab52.cpp2
-rw-r--r--src/mame/drivers/silkroad.cpp2
-rw-r--r--src/mame/drivers/silvmil.cpp2
-rw-r--r--src/mame/drivers/simpsons.cpp2
-rw-r--r--src/mame/drivers/skyfox.cpp2
-rw-r--r--src/mame/drivers/skylncr.cpp25
-rw-r--r--src/mame/drivers/slapshot.cpp4
-rw-r--r--src/mame/drivers/slc1.cpp342
-rw-r--r--src/mame/drivers/slc1a.cpp210
-rw-r--r--src/mame/drivers/smotor.cpp2
-rw-r--r--src/mame/drivers/sms_bootleg.cpp88
-rw-r--r--src/mame/drivers/snesb.cpp744
-rw-r--r--src/mame/drivers/snk.cpp4
-rw-r--r--src/mame/drivers/snk68.cpp2
-rw-r--r--src/mame/drivers/snowbros.cpp83
-rw-r--r--src/mame/drivers/sorcerer.cpp19
-rw-r--r--src/mame/drivers/sothello.cpp2
-rw-r--r--src/mame/drivers/spbactn.cpp2
-rw-r--r--src/mame/drivers/spdheat.cpp2
-rw-r--r--src/mame/drivers/spdodgeb.cpp2
-rw-r--r--src/mame/drivers/speedbal.cpp2
-rw-r--r--src/mame/drivers/spg110.cpp2
-rw-r--r--src/mame/drivers/spg2xx.cpp30
-rw-r--r--src/mame/drivers/spg2xx_jakks_gkr.cpp80
-rw-r--r--src/mame/drivers/spinb.cpp36
-rw-r--r--src/mame/drivers/splash.cpp4
-rw-r--r--src/mame/drivers/splash_ms.cpp2
-rw-r--r--src/mame/drivers/spoker.cpp2
-rw-r--r--src/mame/drivers/sprint2.cpp286
-rw-r--r--src/mame/drivers/spy.cpp2
-rw-r--r--src/mame/drivers/srumbler.cpp2
-rw-r--r--src/mame/drivers/sshangha.cpp2
-rw-r--r--src/mame/drivers/stadhero.cpp4
-rw-r--r--src/mame/drivers/stfight.cpp47
-rw-r--r--src/mame/drivers/storio.cpp14
-rw-r--r--src/mame/drivers/stv.cpp146
-rw-r--r--src/mame/drivers/subhuntr.cpp366
-rw-r--r--src/mame/drivers/subsino.cpp3
-rw-r--r--src/mame/drivers/subsino2.cpp2
-rw-r--r--src/mame/drivers/suna16.cpp4
-rw-r--r--src/mame/drivers/suna8.cpp4
-rw-r--r--src/mame/drivers/supduck.cpp11
-rw-r--r--src/mame/drivers/super80.cpp26
-rw-r--r--src/mame/drivers/supracan.cpp102
-rw-r--r--src/mame/drivers/suprgolf.cpp2
-rw-r--r--src/mame/drivers/suprnova.cpp606
-rw-r--r--src/mame/drivers/suprslam.cpp2
-rw-r--r--src/mame/drivers/surpratk.cpp2
-rw-r--r--src/mame/drivers/sweetland.cpp2
-rw-r--r--src/mame/drivers/system16.cpp5
-rw-r--r--src/mame/drivers/tail2nos.cpp2
-rw-r--r--src/mame/drivers/taito_b.cpp9
-rw-r--r--src/mame/drivers/taito_f2.cpp3
-rw-r--r--src/mame/drivers/taito_f3.cpp356
-rw-r--r--src/mame/drivers/taito_h.cpp2
-rw-r--r--src/mame/drivers/taito_l.cpp3
-rw-r--r--src/mame/drivers/taito_o.cpp2
-rw-r--r--src/mame/drivers/taito_x.cpp6
-rw-r--r--src/mame/drivers/taito_z.cpp2
-rw-r--r--src/mame/drivers/taitoair.cpp2
-rw-r--r--src/mame/drivers/taitogn.cpp4
-rw-r--r--src/mame/drivers/taitosj.cpp520
-rw-r--r--src/mame/drivers/taitotz.cpp57
-rw-r--r--src/mame/drivers/taotaido.cpp2
-rw-r--r--src/mame/drivers/tasc.cpp191
-rw-r--r--src/mame/drivers/tbowl.cpp2
-rw-r--r--src/mame/drivers/tceptor.cpp3
-rw-r--r--src/mame/drivers/tecmo.cpp3
-rw-r--r--src/mame/drivers/tecmo16.cpp2
-rw-r--r--src/mame/drivers/tecmosys.cpp2
-rw-r--r--src/mame/drivers/tek410x.cpp266
-rw-r--r--src/mame/drivers/tek440x.cpp149
-rw-r--r--src/mame/drivers/tekigw.cpp602
-rw-r--r--src/mame/drivers/terracre.cpp6
-rw-r--r--src/mame/drivers/thedeep.cpp2
-rw-r--r--src/mame/drivers/thomson.cpp625
-rw-r--r--src/mame/drivers/thunderx.cpp2
-rw-r--r--src/mame/drivers/ti74.cpp68
-rw-r--r--src/mame/drivers/tigeroad.cpp11
-rw-r--r--src/mame/drivers/timelimt.cpp6
-rw-r--r--src/mame/drivers/tmnt.cpp6
-rw-r--r--src/mame/drivers/tnzs.cpp4
-rw-r--r--src/mame/drivers/toaplan2.cpp4
-rw-r--r--src/mame/drivers/toki.cpp2
-rw-r--r--src/mame/drivers/toki_ms.cpp2
-rw-r--r--src/mame/drivers/tomcat.cpp2
-rw-r--r--src/mame/drivers/topspeed.cpp2
-rw-r--r--src/mame/drivers/travrusa.cpp3
-rw-r--r--src/mame/drivers/trs80.cpp301
-rw-r--r--src/mame/drivers/trs80m3.cpp19
-rw-r--r--src/mame/drivers/tryout.cpp2
-rw-r--r--src/mame/drivers/tsamurai.cpp76
-rw-r--r--src/mame/drivers/tumbleb.cpp4
-rw-r--r--src/mame/drivers/twin16.cpp2
-rw-r--r--src/mame/drivers/twincobr.cpp2
-rw-r--r--src/mame/drivers/ultraman.cpp2
-rw-r--r--src/mame/drivers/umipoker.cpp2
-rw-r--r--src/mame/drivers/unico.cpp4
-rw-r--r--src/mame/drivers/unixpc.cpp3
-rw-r--r--src/mame/drivers/vamphalf.cpp16
-rw-r--r--src/mame/drivers/vaportra.cpp4
-rw-r--r--src/mame/drivers/vball.cpp2
-rw-r--r--src/mame/drivers/vectrex.cpp2
-rw-r--r--src/mame/drivers/vegas.cpp7
-rw-r--r--src/mame/drivers/vendetta.cpp2
-rw-r--r--src/mame/drivers/vgmplay.cpp88
-rw-r--r--src/mame/drivers/vicdual.cpp152
-rw-r--r--src/mame/drivers/vigilant.cpp4
-rw-r--r--src/mame/drivers/vis.cpp2
-rw-r--r--src/mame/drivers/volfied.cpp2
-rw-r--r--src/mame/drivers/vt1682.cpp8
-rw-r--r--src/mame/drivers/vtech1.cpp19
-rw-r--r--src/mame/drivers/vtech2.cpp5
-rw-r--r--src/mame/drivers/vtech_innotab.cpp218
-rw-r--r--src/mame/drivers/vulgus.cpp5
-rw-r--r--src/mame/drivers/wacky_gator.cpp2
-rw-r--r--src/mame/drivers/wardner.cpp2
-rw-r--r--src/mame/drivers/warriorb.cpp4
-rw-r--r--src/mame/drivers/wc90.cpp2
-rw-r--r--src/mame/drivers/wc90b.cpp2
-rw-r--r--src/mame/drivers/wecleman.cpp4
-rw-r--r--src/mame/drivers/welltris.cpp2
-rw-r--r--src/mame/drivers/wgp.cpp2
-rw-r--r--src/mame/drivers/wrally.cpp34
-rw-r--r--src/mame/drivers/wwfsstar.cpp2
-rw-r--r--src/mame/drivers/wy85.cpp5
-rw-r--r--src/mame/drivers/x68k.cpp5
-rw-r--r--src/mame/drivers/xain.cpp2
-rw-r--r--src/mame/drivers/xerox820.cpp70
-rw-r--r--src/mame/drivers/xexex.cpp2
-rw-r--r--src/mame/drivers/xmen.cpp2
-rw-r--r--src/mame/drivers/xxmissio.cpp2
-rw-r--r--src/mame/drivers/yes.cpp80
-rw-r--r--src/mame/drivers/ymdx11.cpp2
-rw-r--r--src/mame/drivers/ymmu5.cpp7
-rw-r--r--src/mame/drivers/ympsr340.cpp10
-rw-r--r--src/mame/drivers/ympsr60.cpp735
-rw-r--r--src/mame/drivers/ymtx81z.cpp51
-rw-r--r--src/mame/drivers/yunsun16.cpp2
-rw-r--r--src/mame/drivers/yunsung8.cpp2
-rw-r--r--src/mame/drivers/yuvomz80.cpp2
-rw-r--r--src/mame/drivers/zn.cpp1119
-rw-r--r--src/mame/drivers/zpinball.cpp9
-rw-r--r--src/mame/drivers/zr107.cpp291
-rw-r--r--src/mame/includes/alpha68k.h5
-rw-r--r--src/mame/includes/amspdwy.h2
-rw-r--r--src/mame/includes/aquarius.h12
-rw-r--r--src/mame/includes/archimds.h168
-rw-r--r--src/mame/includes/atarisy1.h2
-rw-r--r--src/mame/includes/atarisy2.h2
-rw-r--r--src/mame/includes/badlands.h2
-rw-r--r--src/mame/includes/bloodbro.h2
-rw-r--r--src/mame/includes/bublbobl.h24
-rw-r--r--src/mame/includes/calomega.h94
-rw-r--r--src/mame/includes/coco.h7
-rw-r--r--src/mame/includes/coco3.h12
-rw-r--r--src/mame/includes/combatsc.h193
-rw-r--r--src/mame/includes/contra.h2
-rw-r--r--src/mame/includes/cop01.h2
-rw-r--r--src/mame/includes/ddribble.h81
-rw-r--r--src/mame/includes/deadang.h2
-rw-r--r--src/mame/includes/deco32.h2
-rw-r--r--src/mame/includes/dragrace.h69
-rw-r--r--src/mame/includes/drgnmst.h2
-rw-r--r--src/mame/includes/exerion.h44
-rw-r--r--src/mame/includes/exterm.h2
-rw-r--r--src/mame/includes/finalizr.h54
-rw-r--r--src/mame/includes/fm7.h2
-rw-r--r--src/mame/includes/fmtowns.h7
-rw-r--r--src/mame/includes/funkyjet.h24
-rw-r--r--src/mame/includes/fuukifg3.h2
-rw-r--r--src/mame/includes/galaxian.h561
-rw-r--r--src/mame/includes/galaxold.h20
-rw-r--r--src/mame/includes/gameplan.h1
-rw-r--r--src/mame/includes/gauntlet.h2
-rw-r--r--src/mame/includes/gng.h2
-rw-r--r--src/mame/includes/h01x.h98
-rw-r--r--src/mame/includes/homedata.h2
-rw-r--r--src/mame/includes/inufuku.h81
-rw-r--r--src/mame/includes/ironhors.h102
-rw-r--r--src/mame/includes/jackal.h71
-rw-r--r--src/mame/includes/jpmsys5.h2
-rw-r--r--src/mame/includes/kaneko16.h2
-rw-r--r--src/mame/includes/kaypro.h1
-rw-r--r--src/mame/includes/kikikai.h22
-rw-r--r--src/mame/includes/ladybug.h66
-rw-r--r--src/mame/includes/laserbat.h117
-rw-r--r--src/mame/includes/lc80.h74
-rw-r--r--src/mame/includes/m79amb.h6
-rw-r--r--src/mame/includes/mac.h11
-rw-r--r--src/mame/includes/macpci.h1
-rw-r--r--src/mame/includes/maygay1b.h2
-rw-r--r--src/mame/includes/mbee.h135
-rw-r--r--src/mame/includes/megadriv.h4
-rw-r--r--src/mame/includes/mermaid.h7
-rw-r--r--src/mame/includes/metro.h2
-rw-r--r--src/mame/includes/mpu4.h2
-rw-r--r--src/mame/includes/msx.h2
-rw-r--r--src/mame/includes/mz2500.h2
-rw-r--r--src/mame/includes/namcos2.h1
-rw-r--r--src/mame/includes/naomi.h3
-rw-r--r--src/mame/includes/neogeo.h2
-rw-r--r--src/mame/includes/nitedrvr.h60
-rw-r--r--src/mame/includes/ojankohs.h175
-rw-r--r--src/mame/includes/pacman.h8
-rw-r--r--src/mame/includes/pc6001.h2
-rw-r--r--src/mame/includes/pc8801.h3
-rw-r--r--src/mame/includes/pc88va.h4
-rw-r--r--src/mame/includes/pc9801.h54
-rw-r--r--src/mame/includes/poly880.h68
-rw-r--r--src/mame/includes/psikyo4.h2
-rw-r--r--src/mame/includes/rampart.h2
-rw-r--r--src/mame/includes/relief.h2
-rw-r--r--src/mame/includes/s11.h2
-rw-r--r--src/mame/includes/saitek_stratos.h8
-rw-r--r--src/mame/includes/segas16a.h2
-rw-r--r--src/mame/includes/segas16b.h4
-rw-r--r--src/mame/includes/seta.h2
-rw-r--r--src/mame/includes/sms.h2
-rw-r--r--src/mame/includes/sms_bootleg.h20
-rw-r--r--src/mame/includes/snowbros.h1
-rw-r--r--src/mame/includes/sorcerer.h1
-rw-r--r--src/mame/includes/sprint2.h86
-rw-r--r--src/mame/includes/stfight.h5
-rw-r--r--src/mame/includes/stv.h15
-rw-r--r--src/mame/includes/supbtime.h2
-rw-r--r--src/mame/includes/taito_f3.h2
-rw-r--r--src/mame/includes/taito_l.h2
-rw-r--r--src/mame/includes/taitosj.h82
-rw-r--r--src/mame/includes/tatsumi.h2
-rw-r--r--src/mame/includes/thomson.h524
-rw-r--r--src/mame/includes/tigeroad.h2
-rw-r--r--src/mame/includes/toaplan1.h2
-rw-r--r--src/mame/includes/trs80.h109
-rw-r--r--src/mame/includes/trs80m3.h10
-rw-r--r--src/mame/includes/witch.h2
-rw-r--r--src/mame/includes/x1.h2
-rw-r--r--src/mame/includes/x68k.h4
-rw-r--r--src/mame/includes/xerox820.h7
-rw-r--r--src/mame/includes/zn.h2
-rw-r--r--src/mame/layout/cambrp.lay22
-rw-r--r--src/mame/layout/cc40.lay62
-rw-r--r--src/mame/layout/chessmst.lay210
-rw-r--r--src/mame/layout/chessmstdm.lay105
-rw-r--r--src/mame/layout/coco3.lay20
-rw-r--r--src/mame/layout/crei680.lay47
-rw-r--r--src/mame/layout/critcrsh.lay30
-rw-r--r--src/mame/layout/enmirage.lay210
-rw-r--r--src/mame/layout/fidel_acr.lay6
-rw-r--r--src/mame/layout/fidel_chesster.lay56
-rw-r--r--src/mame/layout/fidel_desdis.lay59
-rw-r--r--src/mame/layout/fidel_desdis_68kg.lay59
-rw-r--r--src/mame/layout/fidel_desdis_68kr.lay59
-rw-r--r--src/mame/layout/gamball.lay14
-rw-r--r--src/mame/layout/j6aceclb.lay304
-rw-r--r--src/mame/layout/j6acehi.lay114
-rw-r--r--src/mame/layout/j6amdrm.lay110
-rw-r--r--src/mame/layout/j6arcadee.lay4421
-rw-r--r--src/mame/layout/j6big50.lay16
-rw-r--r--src/mame/layout/j6bigbukc.lay78
-rw-r--r--src/mame/layout/j6bigtopa.lay11
-rw-r--r--src/mame/layout/j6bnkrcl.lay115
-rw-r--r--src/mame/layout/j6bnza.lay294
-rw-r--r--src/mame/layout/j6btbwd.lay115
-rw-r--r--src/mame/layout/j6camelt.lay28
-rw-r--r--src/mame/layout/j6casclaf.lay115
-rw-r--r--src/mame/layout/j6cascze.lay137
-rw-r--r--src/mame/layout/j6colcsh.lay4363
-rw-r--r--src/mame/layout/j6cpal.lay115
-rw-r--r--src/mame/layout/j6crack.lay115
-rw-r--r--src/mame/layout/j6drdogh.lay4776
-rw-r--r--src/mame/layout/j6euphor.lay115
-rw-r--r--src/mame/layout/j6ewn.lay115
-rw-r--r--src/mame/layout/j6fastfr.lay115
-rw-r--r--src/mame/layout/j6ffce.lay115
-rw-r--r--src/mame/layout/j6frtpot.lay115
-rw-r--r--src/mame/layout/j6gidogh.lay115
-rw-r--r--src/mame/layout/j6gldclb.lay115
-rw-r--r--src/mame/layout/j6gogold.lay115
-rw-r--r--src/mame/layout/j6goldgla.lay115
-rw-r--r--src/mame/layout/j6guabc.lay71
-rw-r--r--src/mame/layout/j6guabcl.lay561
-rw-r--r--src/mame/layout/j6hapyhrb.lay55
-rw-r--r--src/mame/layout/j6impuls.lay5
-rw-r--r--src/mame/layout/j6impuls15.lay5
-rw-r--r--src/mame/layout/j6indy6.lay3976
-rw-r--r--src/mame/layout/j6indy8.lay3976
-rw-r--r--src/mame/layout/j6kfc.lay115
-rw-r--r--src/mame/layout/j6kungfu.lay11
-rw-r--r--src/mame/layout/j6megbck.lay115
-rw-r--r--src/mame/layout/j6mono60.lay492
-rw-r--r--src/mame/layout/j6mono6010.lay (renamed from src/mame/layout/j6rico.lay)3770
-rw-r--r--src/mame/layout/j6mono608.lay (renamed from src/mame/layout/j6indyi.lay)3779
-rw-r--r--src/mame/layout/j6monst.lay115
-rw-r--r--src/mame/layout/j6montlk.lay55
-rw-r--r--src/mame/layout/j6montlk6.lay55
-rw-r--r--src/mame/layout/j6oxobin.lay5464
-rw-r--r--src/mame/layout/j6oxobin10.lay2235
-rw-r--r--src/mame/layout/j6quick.lay277
-rw-r--r--src/mame/layout/j6ra.lay115
-rw-r--r--src/mame/layout/j6redarwf.lay115
-rw-r--r--src/mame/layout/j6reelmn.lay5489
-rw-r--r--src/mame/layout/j6rh6cld.lay115
-rw-r--r--src/mame/layout/j6rhchil.lay115
-rw-r--r--src/mame/layout/j6rico10.lay4144
-rw-r--r--src/mame/layout/j6roller10.lay55
-rw-r--r--src/mame/layout/j6roller15.lay115
-rw-r--r--src/mame/layout/j6roller8.lay55
-rw-r--r--src/mame/layout/j6slagng.lay115
-rw-r--r--src/mame/layout/j6snakes.lay4496
-rw-r--r--src/mame/layout/j6sonic10.lay3780
-rw-r--r--src/mame/layout/j6stards.lay4665
-rw-r--r--src/mame/layout/j6swpdrp.lay115
-rw-r--r--src/mame/layout/j6tombc.lay115
-rw-r--r--src/mame/layout/j6topflg.lay115
-rw-r--r--src/mame/layout/j6twst.lay115
-rw-r--r--src/mame/layout/j6untch.lay3934
-rw-r--r--src/mame/layout/j6vindal.lay115
-rw-r--r--src/mame/layout/j6vivark.lay115
-rw-r--r--src/mame/layout/j6wizardd.lay4523
-rw-r--r--src/mame/layout/j6wldkng.lay5896
-rw-r--r--src/mame/layout/jpmimpct.lay16
-rw-r--r--src/mame/layout/jpmsys5.lay17
-rw-r--r--src/mame/layout/kenokb.lay195
-rw-r--r--src/mame/layout/kn01.lay30
-rw-r--r--src/mame/layout/lc80.lay72
-rw-r--r--src/mame/layout/m4actbnk.lay2193
-rw-r--r--src/mame/layout/m4actpak.lay2697
-rw-r--r--src/mame/layout/m4andybt.lay4803
-rw-r--r--src/mame/layout/m4andycp.lay2451
-rw-r--r--src/mame/layout/m4andyfh.lay939
-rw-r--r--src/mame/layout/m4andyge.lay1905
-rw-r--r--src/mame/layout/m4apachg.lay2976
-rw-r--r--src/mame/layout/m4tenten.lay1962
-rw-r--r--src/mame/layout/mephisto_1.lay26
-rw-r--r--src/mame/layout/mephisto_3.lay26
-rw-r--r--src/mame/layout/mephisto_amsterdam.lay26
-rw-r--r--src/mame/layout/mephisto_bup.lay26
-rw-r--r--src/mame/layout/mephisto_esb2.lay26
-rw-r--r--src/mame/layout/mephisto_glasgow.lay26
-rw-r--r--src/mame/layout/mephisto_junior.lay26
-rw-r--r--src/mame/layout/mephisto_mirage.lay26
-rw-r--r--src/mame/layout/mephisto_mm1.lay26
-rw-r--r--src/mame/layout/mephisto_mm2.lay26
-rw-r--r--src/mame/layout/mephisto_modena.lay27
-rw-r--r--src/mame/layout/mephisto_mondial.lay109
-rw-r--r--src/mame/layout/mephisto_mondial2.lay109
-rw-r--r--src/mame/layout/mephisto_mondial68k.lay98
-rw-r--r--src/mame/layout/mephisto_montec.lay4
-rw-r--r--src/mame/layout/mephisto_montreux.lay533
-rw-r--r--src/mame/layout/mephisto_polgar.lay6
-rw-r--r--src/mame/layout/mephisto_risc.lay6
-rw-r--r--src/mame/layout/mephisto_smondial.lay110
-rw-r--r--src/mame/layout/mephisto_smondial2.lay84
-rw-r--r--src/mame/layout/mg1.lay36
-rw-r--r--src/mame/layout/mirage.lay27
-rw-r--r--src/mame/layout/missamer.lay1361
-rw-r--r--src/mame/layout/mpu3.lay8
-rw-r--r--src/mame/layout/mpu4.lay10
-rw-r--r--src/mame/layout/mpu4ext.lay18
-rw-r--r--src/mame/layout/poly880.lay42
-rw-r--r--src/mame/layout/psr60.lay1115
-rw-r--r--src/mame/layout/psr70.lay1040
-rw-r--r--src/mame/layout/saitek_galileo.lay669
-rw-r--r--src/mame/layout/saitek_leonardo.lay360
-rw-r--r--src/mame/layout/saitek_renaissance.lay295
-rw-r--r--src/mame/layout/saitek_risc2500.lay367
-rw-r--r--src/mame/layout/sbuk2.lay36
-rw-r--r--src/mame/layout/sbuk2a.lay213
-rw-r--r--src/mame/layout/sc1_vfd.lay22
-rw-r--r--src/mame/layout/sc2_vfd.lay12
-rw-r--r--src/mame/layout/slc1.lay63
-rw-r--r--src/mame/layout/slc1a.lay25
-rw-r--r--src/mame/layout/tascr30.lay8
-rw-r--r--src/mame/layout/ti74.lay56
-rw-r--r--src/mame/layout/ti95.lay70
-rw-r--r--src/mame/layout/tx81z.lay240
-rw-r--r--src/mame/layout/warp1bl.lay29
-rw-r--r--src/mame/machine/315_5338a.cpp22
-rw-r--r--src/mame/machine/315_5338a.h1
-rw-r--r--src/mame/machine/6883sam.cpp81
-rw-r--r--src/mame/machine/apple3.cpp49
-rw-r--r--src/mame/machine/archimds.cpp1018
-rw-r--r--src/mame/machine/basf7100_kbd.cpp300
-rw-r--r--src/mame/machine/basf7100_kbd.h61
-rw-r--r--src/mame/machine/bingoct.cpp305
-rw-r--r--src/mame/machine/bingoct.h61
-rw-r--r--src/mame/machine/bublbobl.cpp63
-rw-r--r--src/mame/machine/coco.cpp138
-rw-r--r--src/mame/machine/coco3.cpp21
-rw-r--r--src/mame/machine/egret.cpp30
-rw-r--r--src/mame/machine/k007452.cpp2
-rw-r--r--src/mame/machine/k573kara.cpp166
-rw-r--r--src/mame/machine/k573kara.h50
-rw-r--r--src/mame/machine/kikikai.cpp64
-rw-r--r--src/mame/machine/konami_gn676_lan.cpp226
-rw-r--r--src/mame/machine/konami_gn676_lan.h42
-rw-r--r--src/mame/machine/mac.cpp59
-rw-r--r--src/mame/machine/macadb.cpp12
-rw-r--r--src/mame/machine/macpci.cpp6
-rw-r--r--src/mame/machine/macscsi.cpp318
-rw-r--r--src/mame/machine/macscsi.h70
-rw-r--r--src/mame/machine/mb87013.cpp150
-rw-r--r--src/mame/machine/mb87013.h90
-rw-r--r--src/mame/machine/mbee.cpp287
-rw-r--r--src/mame/machine/megadriv.cpp2
-rw-r--r--src/mame/machine/midwayic.cpp18
-rw-r--r--src/mame/machine/midwayic.h1
-rw-r--r--src/mame/machine/mmboard.cpp20
-rw-r--r--src/mame/machine/mmboard.h32
-rw-r--r--src/mame/machine/nb1412m2.cpp30
-rw-r--r--src/mame/machine/nb1412m2.h4
-rw-r--r--src/mame/machine/nitedrvr.cpp78
-rw-r--r--src/mame/machine/nmk004.cpp2
-rw-r--r--src/mame/machine/pofo_kbd.cpp138
-rw-r--r--src/mame/machine/pofo_kbd.h39
-rw-r--r--src/mame/machine/segashiobd.cpp121
-rw-r--r--src/mame/machine/segashiobd.h29
-rw-r--r--src/mame/machine/slapstic.cpp2
-rw-r--r--src/mame/machine/smartboard.h59
-rw-r--r--src/mame/machine/sms.cpp17
-rw-r--r--src/mame/machine/sorcerer.cpp197
-rw-r--r--src/mame/machine/stfight.cpp15
-rw-r--r--src/mame/machine/stvprot.cpp94
-rw-r--r--src/mame/machine/stvprot.h2
-rw-r--r--src/mame/machine/taitosj.cpp53
-rw-r--r--src/mame/machine/tek410x_kbd.cpp385
-rw-r--r--src/mame/machine/tek410x_kbd.h69
-rw-r--r--src/mame/machine/thomflop.cpp1867
-rw-r--r--src/mame/machine/thomflop.h159
-rw-r--r--src/mame/machine/thomson.cpp482
-rw-r--r--src/mame/machine/toaplan1.cpp2
-rw-r--r--src/mame/machine/trs80.cpp81
-rw-r--r--src/mame/machine/trs80m3.cpp25
-rw-r--r--src/mame/mame.lst319
-rw-r--r--src/mame/mess.flt16
-rw-r--r--src/mame/video/1942.cpp16
-rw-r--r--src/mame/video/1943.cpp9
-rw-r--r--src/mame/video/aquarius.cpp49
-rw-r--r--src/mame/video/avgdvg.cpp3
-rw-r--r--src/mame/video/battlane.cpp8
-rw-r--r--src/mame/video/blktiger.cpp9
-rw-r--r--src/mame/video/calomega.cpp46
-rw-r--r--src/mame/video/combatsc.cpp176
-rw-r--r--src/mame/video/commando.cpp7
-rw-r--r--src/mame/video/cop01.cpp2
-rw-r--r--src/mame/video/ddribble.cpp75
-rw-r--r--src/mame/video/dragrace.cpp12
-rw-r--r--src/mame/video/exerion.cpp93
-rw-r--r--src/mame/video/finalizr.cpp32
-rw-r--r--src/mame/video/fmtowns.cpp85
-rw-r--r--src/mame/video/funkyjet.cpp16
-rw-r--r--src/mame/video/galaxian.cpp113
-rw-r--r--src/mame/video/galaxold.cpp53
-rw-r--r--src/mame/video/gameplan.cpp3
-rw-r--r--src/mame/video/gime.cpp179
-rw-r--r--src/mame/video/gime.h7
-rw-r--r--src/mame/video/gng.cpp7
-rw-r--r--src/mame/video/gunsmoke.cpp7
-rw-r--r--src/mame/video/h01x.cpp43
-rw-r--r--src/mame/video/inufuku.cpp173
-rw-r--r--src/mame/video/ironhors.cpp72
-rw-r--r--src/mame/video/jackal.cpp73
-rw-r--r--src/mame/video/k001005.cpp14
-rw-r--r--src/mame/video/k037122.cpp155
-rw-r--r--src/mame/video/k037122.h10
-rw-r--r--src/mame/video/ladybug.cpp34
-rw-r--r--src/mame/video/laserbat.cpp26
-rw-r--r--src/mame/video/mbee.cpp11
-rw-r--r--src/mame/video/megasys1.cpp2
-rw-r--r--src/mame/video/mermaid.cpp78
-rw-r--r--src/mame/video/mmdisplay1.cpp1
-rw-r--r--src/mame/video/mmdisplay2.cpp20
-rw-r--r--src/mame/video/mmdisplay2.h21
-rw-r--r--src/mame/video/namco_c45road.cpp11
-rw-r--r--src/mame/video/namco_c45road.h3
-rw-r--r--src/mame/video/namcos2.cpp2
-rw-r--r--src/mame/video/namcos2_sprite.cpp55
-rw-r--r--src/mame/video/namcos2_sprite.h32
-rw-r--r--src/mame/video/nitedrvr.cpp2
-rw-r--r--src/mame/video/ojankohs.cpp81
-rw-r--r--src/mame/video/pacman.cpp68
-rw-r--r--src/mame/video/seta001.cpp8
-rw-r--r--src/mame/video/sprint2.cpp90
-rw-r--r--src/mame/video/taito_f3.cpp4
-rw-r--r--src/mame/video/taitosj.cpp223
-rw-r--r--src/mame/video/thomson.cpp56
-rw-r--r--src/mame/video/tigeroad.cpp5
-rw-r--r--src/mame/video/tigeroad_spr.cpp2
-rw-r--r--src/mame/video/trs80.cpp166
-rw-r--r--src/mame/video/tutankhm.cpp21
-rw-r--r--src/mame/video/vulgus.cpp7
-rw-r--r--src/mame/video/x68k.cpp222
-rw-r--r--src/mame/video/x68k_crtc.cpp144
-rw-r--r--src/mame/video/x68k_crtc.h1
-rw-r--r--src/osd/eigcc.h60
-rw-r--r--src/osd/eigccarm.h62
-rw-r--r--src/osd/eigccppc.h62
-rw-r--r--src/osd/eigccx86.h64
-rw-r--r--src/osd/eivc.h57
-rw-r--r--src/osd/eivcarm.h75
-rw-r--r--src/osd/eminline.h47
-rw-r--r--src/osd/modules/debugger/debuggdbstub.cpp67
-rw-r--r--src/osd/modules/debugger/debugimgui.cpp3
-rw-r--r--src/osd/modules/debugger/qt/dasmwindow.cpp7
-rw-r--r--src/osd/modules/debugger/qt/memorywindow.cpp31
-rw-r--r--src/osd/modules/input/input_sdl.cpp28
-rw-r--r--src/osd/modules/sound/pulse_sound.cpp12
-rw-r--r--src/osd/sdl/osdsdl.h4
-rw-r--r--src/osd/sdl/sdlmain.cpp3
-rw-r--r--src/osd/sdl/window.cpp62
-rw-r--r--src/osd/windows/winmain.cpp1
-rw-r--r--src/tools/floptool.cpp906
-rw-r--r--src/tools/image_handler.cpp481
-rw-r--r--src/tools/image_handler.h121
-rw-r--r--src/tools/imgtool/formats/vt_dsk_legacy.cpp (renamed from src/tools/imgtool/formats/vt_dsk.cpp)6
-rw-r--r--src/tools/imgtool/formats/vt_dsk_legacy.h (renamed from src/tools/imgtool/formats/vt_dsk.h)10
-rw-r--r--src/tools/imgtool/modules/vzdos.cpp2
-rw-r--r--src/tools/unidasm.cpp186
1619 files changed, 261607 insertions, 204153 deletions
diff --git a/3rdparty/ymfm/.editorconfig b/3rdparty/ymfm/.editorconfig
new file mode 100644
index 00000000000..29f634bbe5e
--- /dev/null
+++ b/3rdparty/ymfm/.editorconfig
@@ -0,0 +1,9 @@
+root = true
+
+[*]
+charset = utf-8
+indent_size = 4
+indent_style = tab
+insert_final_newline = true
+tab_width = 4
+trim_trailing_whitespace = true
diff --git a/3rdparty/ymfm/.gitignore b/3rdparty/ymfm/.gitignore
new file mode 100644
index 00000000000..69111d94505
--- /dev/null
+++ b/3rdparty/ymfm/.gitignore
@@ -0,0 +1,39 @@
+# Prerequisites
+*.d
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
+
+# Symbol/intermediate files
+*.pdb
+*.ilk
+
+# VS Code stuff
+.vs/
diff --git a/3rdparty/ymfm/GeneralInfo.md b/3rdparty/ymfm/GeneralInfo.md
new file mode 100644
index 00000000000..52cdbf5e81b
--- /dev/null
+++ b/3rdparty/ymfm/GeneralInfo.md
@@ -0,0 +1,282 @@
+# ymfm: One FM core to rule them all
+
+The ymfm emulator ws written from the ground-up using the analysis and deduction by Nemesis as a starting point, particularly in [this thread](https://gendev.spritesmind.net/forum/viewtopic.php?f=24&t=386).
+
+The core assumption is that these details apply to all FM variants unless otherwise proven incorrect.
+
+The fine details of this implementation have also been cross-checked against Nemesis' implementation in his [Exodus emulator](https://www.exodusemulator.com/), as well as Alexey Khokholov's ["Nuked" implementations](https://github.com/nukeykt/Nuked-OPN2) based off die shots.
+
+Operator and channel summing/mixing code for OPM and OPN is largely based off of research done by [David Viens](https://twitter.com/plgDavid) and Hubert Lamontagne.
+
+## Families
+
+The Yamaha FM chips can be broadly categoried into families:
+
+* OPM (YM2151)
+ * OPP (YM2164)
+* OPN (YM2203)
+ * OPNA/OPNB/OPN2 (YM2608, YM2610, YM2610B, YM2612, YM3438, YMF276, YMF288)
+* OPL (YM3526)
+ * OPL2 (YM3812)
+ * OPLL (YM2413, YM2423, YMF281, DS1001, and others)
+ * OPL3 (YMF262, YMF289B)
+ * OPL4 (YMF278)
+
+Additionally, several lesser-documented variants exist exclusively in the employ of Yamaha synthesizers:
+
+* OPQ (YM3608)
+* OPZ (YM2414)
+
+All of these families are very closely related, and the ymfm engine is designed to be universal to work across all of
+these families.
+
+Of course, each variant has its own register maps, features, and implementation details which need to be sorted out.
+Thus, each significant variant listed above is represented by a register class.
+The register class contains:
+
+* constants describing core parameters and features
+* mappers between operators and channels
+* generic fetchers that return normalized values across families
+* family-specific implementations of LFO and phase calculations
+
+## Family History
+
+This history outlines the progress of adding/removing features across the three main families (OPM, OPN, OPL):
+
+OPM started it all off, featuring:
+* 8 FM channels, 4 operators each
+* LFO and noise support
+* Stereo output
+
+OPM -> OPN changes:
+* Reduced to 3 FM channels, 4 operators each
+* Removed LFO and noise support
+* Mono output
+* Integrated AY-8910 compatible PSG
+* Added SSG-EG envelope mode
+* Added multi-frequency mode: ch. 3 operators can have separate frequencies
+* Software controlled clock divider
+
+OPN -> OPNA changes:
+* Increased to 6 FM channels, 4 operators each
+* Added back (a cut-down) LFO
+* Stereo output again
+* Removed software controlled divider on later versions (OPNB/OPN2)
+* Removed PSG on OPN2 models
+
+OPNA -> OPL changes:
+* Increased to 9 FM channels, but only 2 operators each
+* Even more simplified LFO
+* Mono output
+* Removed PSG
+* Removed SSG-EG envelope modes
+* Removed multi-frequency modes
+* Fixed clock divider
+* Built-in ryhthm generation
+
+OPL -> OPL2 changes:
+* Added 4 selectable waveforms
+
+OPL2 -> OPLL changes:
+* Vastly simplified register map
+* 15 built-in instruments, plus built-in rhythm instruments
+* 1 user-controlled instrument
+
+OPL2 -> OPL3 changes:
+* Increased to 18 FM channels, 2 operators each
+* 4 output channels
+* Increased to 8 selectable waveforms
+* 6 channels can be configured to use 4 operators
+
+## Channels and Operators
+
+The polyphony of a given chip is determined by the number of channels it supports.
+This number ranges from as low as 3 to as high as 18.
+Each channel has either 2 or 4 operators that can be combined in a myriad of ways.
+On most chips the number of operators per channel is fixed; however, some later OPL chips allow this to be toggled between 2 and 4 at runtime.
+
+The base ymfm engine class maintains an array of channels and operators, while the relationship between the two is described by the register class.
+
+## Registers
+
+Registers on the Yamaha chips are generally write-only, and can be divided into three distinct categories:
+
+* system-wide registers
+* channel-specific registers
+* operator-specific registers
+
+For maximum flexibility, most parameters can be configured at the operator level, with channel-level registers controlling details such as how to combine the operators into the final output.
+System-wide registers are used to control chip-wide modes and manage onboard timer functions.
+
+Note that since registers are write-only, some ymfm register classes will use "holes" in the register space to store additional values that may be needed.
+
+## Attenuation
+
+Most of the computations of the FM engines are done in terms of attenuation, and thus are logarithmic in nature.
+The maximum resolution used internally is 12 bits, as returned by the sin table:
+
+Bit | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
+----|----|----|----|----|----|----|-----|------|-------|--------|---------|---------
+ dB | -96| -48| -24| -12| -6| -3| -1.5| -0.75| -0.375| -0.1875| -0.09375| -0.046875
+
+The envelope generator internally uses 10 bits:
+
+Bit | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+----|----|----|----|----|----|-----|------|-------|--------|---------|
+ dB | -48| -24| -12| -6| -3| -1.5| -0.75| -0.375| -0.1875| -0.09375|
+
+Total level for operators is usually represented by 7 bits:
+
+Bit | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+----|----|----|----|----|----|-----|------|
+ dB | -48| -24| -12| -6| -3| -1.5| -0.75|
+
+Sustain level in the envelope generator is usually represented by 4 bits:
+
+Bit | 3 | 2 | 1 | 0 |
+----|----|----|----|----|
+ dB | -24| -12| -6| -3|
+
+## Status and Timers
+
+Generically, all chips (except OPLL) support two timers that can be programmed to fire and signal IRQs.
+These timers also set bits in the status register.
+The behavior of these bits is shared across all implementations, even if the exact bit positions shift (this is controlled by constants in the registers class).
+
+In addition, several chips incorporate ADPCM decoders which also may set bits in the same status register.
+For this reason, it is possible to control various bits in the status register via the `set_reset_status()` function directly.
+Any active bits that are set and which are not masked (mask is controlled by `set_irq_mask()`), lead to an IRQ being signalled.
+
+Thus, it is possible for the chip-specific implementations to set the mask and control the status register bits such that IRQs are signalled via the same mechanism as timer signals.
+
+In addition, the OPM and OPN families have a "busy" flag, which is set after each write, indicating that another write should not be performed.
+Historically, the duration of this flag was constant and had nothing to do with the internals of the chip.
+However, since the details can potentially vary chip-to-chip, it is the chip's responsibility to insert the busy flag into the status before returning it to the caller.
+
+## Clocking
+
+Each of the Yamaha chips works by cycling through all operators one at a time.
+Thus, the effective output rate of the chips is related to the input clock divided by the number of operators.
+In addition, the input clock is prescaled by an amount.
+Generally, this is a fixed value, though some early OPN chips allow this to be selected at runtime from a small
+number of values.
+
+## Channel Frequencies
+
+One major difference between OPM and later families is in how frequencies are specified.
+OPM specifies frequency via a 3-bit 'block' (aka octave), combined with a 4-bit 'key code' (note number) and a 6-bit 'key fraction'.
+The key code and fraction are converted on the chip into an x.11 fixed-point value and then shifted by the block to produce the final step value for the phase.
+
+Later families, on the other hand, specify frequencies via a 3-bit 'block' just as on OPM, but combined with a 9-12-bit 'frequency number' or 'fnum', which is directly shifted by the block to produce the step value.
+So essentially, later chips make the user do the conversion from note value to phase increment, while OPM is programmed in a more 'musical' way, specifying notes and cents.
+
+Internally, this is abstracted away into a 'block_freq' value, which is a 16-bit value containing the block and frequency info concatenated together as follows:
+
+* OPM: `[3-bit block]:[4-bit keycode]:[6-bit fraction] = 13 bits total`
+
+* OPZ: `[3-bit block]:[12-bit fnum] = 15 bits total`
+* OPN: `[3-bit block]:[11-bit fnum] 0 = 15 bits total`
+* OPL: `[3-bit block]:[10-bit fnum]:00 = 15 bits total`
+* OPLL: `[3-bit block]:[ 9-bit fnum]:000 = 15 bits total`
+
+The register classes handle the raw format directly and convert it into a phase increment which can be used by the generic engine.
+
+## Low Frequency Oscillator (LFO)
+
+The LFO engines are different in several key ways.
+The OPM LFO engine is fairly intricate.
+It has a 4.4 floating-point rate which allows for a huge range of frequencies, and can select between four different waveforms (sawtooth, square, triangle, or noise).
+Separate 7-bit depth controls for AM and PM control the amount of modulation applied in each case.
+This global LFO value is then further controlled at the channel level by a 2-bit AM sensitivity and a 3-bit PM sensitivity, and each operator has a 1-bit AM on/off switch.
+
+For OPN the LFO engine was removed entirely, but a limited version was put back in OPNA and later chips.
+This stripped-down version offered only a 3-bit rate setting (versus the 4.4 floating-point rate in OPN), and no
+global depth control.
+It did bring back the channel-level sensitivity controls and the operator-level on/off control.
+
+For OPL, the LFO is simplified again, with AM and PM running at fixed frequencies, and simple enable flags at the operator level for each controlling their application.
+
+## Differences Between Families
+
+The table below provides some high level functional differences between the differnet families:
+
+subfamily: | OPM | OPN | OPNA | OPL | OPL2 | OPLL | OPL3 |
+------------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:|
+outputs: | 2 | 1 | 2 | 1 | 1 | 1 | 4 |
+channels: | 8 | 3 | 6 | 9 | 9 | 9 | 18 |
+operators: | 32 | 12 | 24 | 18 | 18 | 18 | 36 |
+waveforms: | 1 | 1 | 1 | 1 | 4 | 2 | 8 |
+instruments: | no | no | no | yes | yes | yes | yes |
+ryhthm: | no | no | no | no | no | yes | no |
+dynamic ops: | no | no | no | no | no | no | yes |
+prescale: | 2 | 2/3/6 | 2/3/6 | 4 | 4 | 4 | 8 |
+EG divider: | 3 | 3 | 3 | 1 | 1 | 1 | 1 |
+EG DP: | no | no | no | no | no | yes | no |
+EG SSG: | no | yes | yes | no | no | no | no |
+mod delay: | no | no | no | yes | yes | yes? | no |
+CSM: | yes | ch 2 | ch 2 | yes | yes | yes | no |
+LFO: | yes | no | yes | yes | yes | yes | yes |
+noise: | yes | no | no | no | no | no | no |
+
+* Outputs represents the number of output channels: 1=mono, 2=stereo, 4=stereo+.
+* Channels represents the number of independent FM channels.
+* Operators represents the number of operators, or "slots" which are assembled into the channels.
+* Waveforms represents the number of different sine-derived waveforms available.
+* Instruments indicates whether the family has built-in instruments.
+* Rhythm indicates whether the family has a built-in rhythm
+* Dynamic ops indicates whether it is possible to switch between 2-operator and 4-operator modes dynamically.
+* Prescale specifies the default clock divider; some chips allow this to be controlled via register writes.
+* EG divider represents the divider applied to the envelope generator clock.
+* EG DP indicates whether the envelope generator includes a DP (depress?) phase at the beginning of each key on.
+* SSG EG indicates whether the envelope generator has SSG-style support.
+* Mod delay indicates whether the connection to the first modulator's input is delayed by 1 sample.
+* CSM indicates whether CSM mode is supported, triggered by timer A.
+* LFO indicates whether LFO is supported.
+* Noise indicates whether one of the operators can be replaced with a noise source.
+
+## Chip Specifics
+
+While OPM is its own thing, the OPN and OPL families have quite a few specific
+implementations, with many differing details beyond the core FM parts. Here are
+some details on the OPN family:
+
+chip ID: | YM2203 | YM2608 | YMF288 | YM2610 | YM2610B | YM2612 | YM3438 | YMF276 |
+---------:|:------:|:------:|:------:|:------:|:-------:|:------:|:------:|:------:|
+aka: | OPN | OPNA | OPN3L | OPNB | OPNB2 | OPN2 | OPN2C | OPN2L |
+FM: | 3 | 6 | 6 | 4 | 6 | 6 | 6 | 6 |
+AY-8910: | 3 | 1 | 1 | 1 | 1 | - | - | - |
+ADPCM-A: | - | 6 int | 6 int | 6 ext | 6 ext | - | - | - |
+ADPCM-B: | - | 1 ext | - | 1 ext | 1 ext | - | - | - |
+DAC: | no | no | no | no | no | yes | yes | yes |
+output: | 10.3fp | 16-bit | 16-bit | 16-bit | 16-bit | 9-bit | 9-bit | 16-bit |
+summing: | adder | adder | adder | adder | adder | muxer | muxer | adder |
+
+* FM represents the number of FM channels available.
+* AY-8910 represents the number of AY-8910-compatible outputs.
+* ADPCM-A represents the number of internal/external ADPCM-A channels present.
+* ADPCM-B represents the number of internal/external ADPCM-B channels present.
+* DAC indicates if a directly-accessible DAC output exists, replacing one channel.
+* Output indicates the output format to the final DAC.
+* Summing indicates whether channels are added or time divided in the output.
+
+OPL has a similar trove of chip variants:
+
+chip ID: | YM3526 | Y8950 | YM3812 | YM2413 | YMF262 | YMF289B | YMF278B |
+------------:|:------:|:-------:|:------:|:------:|:------:|:-------:|:-------:|
+aka: | OPL |MSX-AUDIO| OPL2 | OPLL | OPL3 | OPL3L | OPL4 |
+FM: | 9 | 9 | 9 | 9 | 18 | 18 | 18 |
+ADPCM-B: | - | 1 ext | - | - | - | - | - |
+wavetable: | - | - | - | - | - | - | 24 |
+instruments: | no | no | no | yes | no | no | no |
+output: | 10.3fp | 10.3fp | 10.3fp | 9-bit | 16-bit | 16-bit | 16-bit |
+summing: | adder | adder | adder | muxer | adder | adder | adder |
+
+* FM represents the number of FM channels available.
+* ADPCM-B represents the number of external ADPCM-B channels present.
+* Wavetable indicates the number of wavetable channels present.
+* Instruments indicates that the chip has built-in instrument selection.
+* Output indicates the output format to the final DAC.
+* Summing indicates whether channels are added or time divided in the output.
+
+There are several close variants of the YM2413 with different sets of built-in instruments.
+These include the YM2423, YMF281, and DS1001 (aka Konami VRC7).
diff --git a/3rdparty/ymfm/LICENSE b/3rdparty/ymfm/LICENSE
new file mode 100644
index 00000000000..f73e841aa27
--- /dev/null
+++ b/3rdparty/ymfm/LICENSE
@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2021, Aaron Giles
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/3rdparty/ymfm/README.md b/3rdparty/ymfm/README.md
new file mode 100644
index 00000000000..86b7dd446f9
--- /dev/null
+++ b/3rdparty/ymfm/README.md
@@ -0,0 +1,118 @@
+# ymfm
+
+[ymfm](https://github.com/aaronsgiles/ymfm) is a collection of BSD-licensed Yamaha FM sound cores (OPM, OPN, OPL, and others), written by [Aaron Giles](https://aarongiles.com)
+
+## Supported environments
+
+This code should compile cleanly in any environment that has C++14 support.
+It has been tested on gcc, clang, and Microsoft Visual C++ 2019.
+
+## Supported chip families
+
+Currently, support is present for the following chips (organized by header file):
+
+* ymfm_opm.h:
+ * YM2151 (OPM)
+ * YM2164 (OPP)
+* ymfm_opn.h:
+ * YM2149 (SSG)
+ * YM2203 (OPN)
+ * YM2608 (OPNA)
+ * YM2610 (OPNB)
+ * YM2610B (OPNB2)
+ * YM2612 (OPN2)
+ * YM3438 (OPN2C)
+ * YMF276 (OPN2L)
+ * YMF288 (OPN3L)
+* ymfm_opl.h:
+ * YM3526 (OPL)
+ * Y8950 (MSX-Audio)
+ * YM3812 (OPL2)
+ * YMF262 (OPL3)
+ * YMF289B (OPL3L)
+ * YMF278B (OPL4)
+ * YM2413 (OPLL)
+ * YM2423 (OPLL-X)
+ * YMF281 (OPLLP)
+ * DS1001 (Konami 053982)
+* ymfm_opq.h:
+ * YM3806 (OPQ) -- preliminary
+* ymfm_opz.h:
+ * YM2414 (OPZ) -- preliminary
+
+There are some obviously-related chips that also are on my horizon but have no implementation as yet:
+
+* YMW-258-F 'GEW8' (aka Sega 315-5560 aka Sega Multi-PCM)
+* YMF271 (OPX)
+
+## History
+
+These cores were originally written during the summer and fall of 2020 as part of the [MAME](https://mamedev.org/) project.
+As such, their design started off heavily based on how MAME works.
+
+The OPM/OPN cores first appeared in MAME 0.230.
+The OPL cores were added in MAME 0.231.
+A further rewrite to abstract MAME dependencies is planned for MAME 0.232.
+
+The goal was threefold:
+1. provide BSD-licensed emulation cores that are more compatible with MAME's core licensing
+1. modernize and unify the code around a common implementation of shared features
+1. improve accuracy where possible based on discoveries made by others
+
+## Accuracy
+
+The goal of these cores is not 100% digital accuracy.
+To achieve that would require full emulation of the pipelines, which would make the code extremely difficult to comprehend.
+It would also make it much harder to share common implementations of features, or to add support for less well-known chip types.
+If you want that level of accuracy, there are [several](https://github.com/nukeykt/Nuked-OPN2) [decap-based](https://github.com/nukeykt/Nuked-OPM) [emulation cores](https://github.com/nukeykt/Nuked-OPLL) out there.
+
+Instead, the main goals are:
+1. Extremely high (audibly indistinguishable) accuracy
+1. Reasonable performance
+1. Clean design with readable code
+1. Clear documentation of the various chips
+
+## General approach
+
+Check out the [examples directory](https://github.com/aaronsgiles/ymfm/tree/main/examples) for some example usage patterns.
+I'm not a big fan of makefiles for simple things, so instructions on how to compile each example are provided at the top.
+
+# IMPORTANT
+
+As of May 2021, the interface to these is still a bit in flux.
+Be prepared when syncing with upstream to make some adjustments.
+
+### Clocking
+
+The general philosophy of the emulators provided here is that they are clock-independent.
+Much like the actual chips, you (the consumer) control the clock; the chips themselves have no idea what time it is.
+They just tick forward each time you ask them to.
+
+The way you move things along is via the `generate()` function, which ticks the internal system forward one or more samples, and writes out an array out chip-specific `output_data`.
+But what, exactly, is a "sample", and how long is it?
+
+This is where the external clock comes in.
+Most of the Yamaha chips are externally clocked in the MHz range.
+They then divide that clock by a factor (sometimes dynamically controllable), and then the internal operators are pipelined to further divide the clock.
+
+For example, the YM2151 internally divides the clock by 2, and has 32 operators to iterate through.
+Thus, for a nominal input lock of 3.58MHz, you end up at around a 55.9kHz sample rate.
+Fortunately, all the chip implementations can compute this for you; just pass the raw external clock value to the `sample_rate()` method and it will hand you back the output sample rate you want.
+
+Then call `generate()` that many times per second to output the results.
+
+But what if I want to output at a "normal" rate, like 44.1kHz?
+Sorry, you'll have to rate convert as needed.
+
+### Reading and Writing
+
+To read or write to the chips, you can call the `read()` and `write()` methods.
+The offset provided corresponds to the addressing input lines in a (hopefully) logical way.
+
+For reads, almost all chips have a status register, which you can read via `read_status()`.
+Some chips have a data port that can be read via `read_data()`.
+And chips with extended addressing may also have `read_status_hi()` and `read_data_hi()`.
+
+For writes, almost all chips have an address register and a data register, and so you can reliably count on there being a `write_address()` and `write_data()` method as well.
+If the chip supports extended addressing, it may also have `write_address_hi()` and `write_data_hi()`.
+
diff --git a/3rdparty/ymfm/buildall.cpp b/3rdparty/ymfm/buildall.cpp
new file mode 100644
index 00000000000..40bd75e2864
--- /dev/null
+++ b/3rdparty/ymfm/buildall.cpp
@@ -0,0 +1,114 @@
+//
+// Simple program that touches all the existing cores to help ensure
+// that everything builds cleanly.
+//
+// Compile with:
+//
+// g++ --std=c++14 -I../../src buildall.cpp ../../src/ymfm_misc.cpp ../../src/ymfm_opl.cpp ../../src/ymfm_opm.cpp ../../src/ymfm_opn.cpp ../../src/ymfm_opq.cpp ../../src/ymfm_opz.cpp ../../src/ymfm_adpcm.cpp ../../src/ymfm_pcm.cpp ../../src/ymfm_ssg.cpp -o buildall.exe
+//
+// or:
+//
+// clang --std=c++14 -I../../src buildall.cpp ../../src/ymfm_misc.cpp ../../src/ymfm_opl.cpp ../../src/ymfm_opm.cpp ../../src/ymfm_opn.cpp ../../src/ymfm_opq.cpp ../../src/ymfm_opz.cpp ../../src/ymfm_adpcm.cpp ../../src/ymfm_pcm.cpp ../../src/ymfm_ssg.cpp -o buildall.exe
+//
+// or:
+//
+// cl -I..\..\src buildall.cpp ..\..\src\ymfm_misc.cpp ..\..\src\ymfm_opl.cpp ..\..\src\ymfm_opm.cpp ..\..\src\ymfm_opn.cpp ..\..\src\ymfm_opq.cpp ..\..\src\ymfm_opz.cpp ..\..\src\ymfm_adpcm.cpp ..\..\src\ymfm_pcm.cpp ..\..\src\ymfm_ssg.cpp /Od /Zi /std:c++14 /EHsc
+//
+
+#include <vector>
+
+#include "ymfm_misc.h"
+#include "ymfm_opl.h"
+#include "ymfm_opm.h"
+#include "ymfm_opn.h"
+#include "ymfm_opq.h"
+#include "ymfm_opz.h"
+
+
+//-------------------------------------------------
+// main - program entry point
+//-------------------------------------------------
+
+template<typename ChipType>
+class chip_wrapper : public ymfm::ymfm_interface
+{
+public:
+ chip_wrapper() :
+ m_chip(*this)
+ {
+ // reset
+ m_chip.reset();
+
+ // save/restore
+ std::vector<uint8_t> buffer;
+ {
+ ymfm::ymfm_saved_state saver(buffer, true);
+ m_chip.save_restore(saver);
+ }
+ {
+ ymfm::ymfm_saved_state restorer(buffer, false);
+ m_chip.save_restore(restorer);
+ }
+
+ // dummy read/write
+ m_chip.read(0);
+ m_chip.write(0, 0);
+
+ // generate
+ typename ChipType::output_data output[20];
+ m_chip.generate(&output[0], ymfm::array_size(output));
+ }
+
+private:
+ ChipType m_chip;
+};
+
+
+//-------------------------------------------------
+// main - program entry point
+//-------------------------------------------------
+
+int main(int argc, char *argv[])
+{
+ // just keep adding chip variants here as they are implemented
+
+ // ymfm_misc.h:
+ chip_wrapper<ymfm::ym2149> test2149;
+
+ // ymfm_opl.h:
+ chip_wrapper<ymfm::ym3526> test3526;
+ chip_wrapper<ymfm::y8950> test8950;
+ chip_wrapper<ymfm::ym3812> test3812;
+ chip_wrapper<ymfm::ymf262> test262;
+ chip_wrapper<ymfm::ymf289b> test289b;
+ chip_wrapper<ymfm::ymf278b> test278b;
+ chip_wrapper<ymfm::ym2413> test2413;
+ chip_wrapper<ymfm::ym2423> test2423;
+ chip_wrapper<ymfm::ymf281> test281;
+ chip_wrapper<ymfm::ds1001> test1001;
+
+ // ymfm_opm.h:
+ chip_wrapper<ymfm::ym2151> test2151;
+ chip_wrapper<ymfm::ym2164> test2164;
+
+ // ymfm_opn.h:
+ chip_wrapper<ymfm::ym2203> test2203;
+ chip_wrapper<ymfm::ym2608> test2608;
+ chip_wrapper<ymfm::ymf288> test288;
+ chip_wrapper<ymfm::ym2610> test2610;
+ chip_wrapper<ymfm::ym2610b> test2610b;
+ chip_wrapper<ymfm::ym2612> test2612;
+ chip_wrapper<ymfm::ym3438> test3438;
+ chip_wrapper<ymfm::ymf276> test276;
+
+ // ymfm_opq.h:
+ chip_wrapper<ymfm::ym3806> test3806;
+ chip_wrapper<ymfm::ym3533> test3533;
+
+ // ymfm_opz.h:
+ chip_wrapper<ymfm::ym2414> test2414;
+
+ printf("Done\n");
+
+ return 0;
+}
diff --git a/3rdparty/ymfm/examples/vgmrender/.gitignore b/3rdparty/ymfm/examples/vgmrender/.gitignore
new file mode 100644
index 00000000000..9daeafb9864
--- /dev/null
+++ b/3rdparty/ymfm/examples/vgmrender/.gitignore
@@ -0,0 +1 @@
+test
diff --git a/3rdparty/ymfm/examples/vgmrender/em_inflate.cpp b/3rdparty/ymfm/examples/vgmrender/em_inflate.cpp
new file mode 100644
index 00000000000..b9d2f428c48
--- /dev/null
+++ b/3rdparty/ymfm/examples/vgmrender/em_inflate.cpp
@@ -0,0 +1,1185 @@
+/*
+ * em_inflate.c - fast in-memory inflate (gzip/zlib decompressor) implementation
+ *
+ * Copyright (C) 2019 Emmanuel Marty
+ *
+ * gzip crc32 computation by Stephen Brumme - zlib-like license included below
+ * adler checksum computation by Mark Adler - zlib license included below
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include "em_inflate.h"
+
+/* Comment out this define to disable checksum verification */
+#define EM_INFLATE_VERIFY_CHECKSUM
+
+/*--- LSB bitreader ---*/
+
+#if defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__)
+#define EM_LSB_BITREADER_64BIT_SHIFTER
+#endif /* defined(_M_X64) */
+
+#ifdef EM_LSB_BITREADER_64BIT_SHIFTER
+typedef unsigned long long em_lsb_bitreader_shifter_t;
+#else
+typedef unsigned int em_lsb_bitreader_shifter_t;
+#endif
+
+/** Bit reader context */
+typedef struct {
+ int nDecShifterBitCount;
+ em_lsb_bitreader_shifter_t nDecShifterData;
+ const unsigned char *pInBlock;
+ const unsigned char *pInBlockEnd;
+ const unsigned char *pInBlockStart;
+} em_lsb_bitreader_t;
+
+/**
+ * Initialize bit reader
+ *
+ * @param pBitReader bit reader context
+ * @param pInBlock pointer to start of compressed block
+ * @param InBlockEnd pointer to end of compressed block + 1
+ */
+static inline void em_lsb_bitreader_init(em_lsb_bitreader_t *pBitReader, const unsigned char *pInBlock, const unsigned char *pInBlockEnd) {
+ pBitReader->nDecShifterBitCount = 0;
+ pBitReader->nDecShifterData = 0;
+ pBitReader->pInBlock = pInBlock;
+ pBitReader->pInBlockEnd = pInBlockEnd;
+ pBitReader->pInBlockStart = pInBlock;
+}
+
+/**
+ * Refill 32 bits at a time if the architecture allows it, otherwise do nothing.
+ *
+ * @param pBitReader bit reader context
+ */
+static inline void em_lsb_bitreader_refill_32(em_lsb_bitreader_t *pBitReader) {
+#ifdef EM_LSB_BITREADER_64BIT_SHIFTER
+ if (pBitReader->nDecShifterBitCount <= 32 && (pBitReader->pInBlock + 4) <= pBitReader->pInBlockEnd) {
+#if defined(_M_X64) || defined(__x86_64__)
+ /* Read unaligned word */
+ pBitReader->nDecShifterData |= (((em_lsb_bitreader_shifter_t)(*((unsigned int*)pBitReader->pInBlock))) << pBitReader->nDecShifterBitCount);
+ pBitReader->nDecShifterBitCount += 32;
+ pBitReader->pInBlock += 4;
+#else
+ /* Read bytes */
+ pBitReader->nDecShifterData |= (((em_lsb_bitreader_shifter_t)(*pBitReader->pInBlock++)) << pBitReader->nDecShifterBitCount);
+ pBitReader->nDecShifterBitCount += 8;
+ pBitReader->nDecShifterData |= (((em_lsb_bitreader_shifter_t)(*pBitReader->pInBlock++)) << pBitReader->nDecShifterBitCount);
+ pBitReader->nDecShifterBitCount += 8;
+ pBitReader->nDecShifterData |= (((em_lsb_bitreader_shifter_t)(*pBitReader->pInBlock++)) << pBitReader->nDecShifterBitCount);
+ pBitReader->nDecShifterBitCount += 8;
+ pBitReader->nDecShifterData |= (((em_lsb_bitreader_shifter_t)(*pBitReader->pInBlock++)) << pBitReader->nDecShifterBitCount);
+ pBitReader->nDecShifterBitCount += 8;
+#endif
+ }
+#endif /* EM_LSB_BITREADER_64BIT_SHIFTER */
+}
+
+/**
+ * Read variable bit-length value
+ *
+ * @param pBitReader bit reader context
+ * @param nBits size of value in bits (number of bits to read), 0..16
+ *
+ * @return value, or -1 for failure
+ */
+static inline unsigned int em_lsb_bitreader_get_bits(em_lsb_bitreader_t *pBitReader, const int nBits) {
+ if (pBitReader->nDecShifterBitCount < nBits) {
+ if (pBitReader->pInBlock < pBitReader->pInBlockEnd) {
+ pBitReader->nDecShifterData |= (((em_lsb_bitreader_shifter_t)(*pBitReader->pInBlock++)) << pBitReader->nDecShifterBitCount);
+ pBitReader->nDecShifterBitCount += 8;
+
+ if (pBitReader->pInBlock < pBitReader->pInBlockEnd) {
+ pBitReader->nDecShifterData |= (((em_lsb_bitreader_shifter_t)(*pBitReader->pInBlock++)) << pBitReader->nDecShifterBitCount);
+ pBitReader->nDecShifterBitCount += 8;
+ }
+ }
+ else
+ return -1;
+ }
+
+ unsigned int nValue = pBitReader->nDecShifterData & ((1 << nBits) - 1);
+ pBitReader->nDecShifterData >>= nBits;
+ pBitReader->nDecShifterBitCount -= nBits;
+ return nValue;
+}
+
+/**
+ * Peek at a 16-bit value in the bitstream (lookahead)
+ *
+ * @param pBitReader bit reader context
+ *
+ * @return value
+ */
+static inline unsigned int em_lsb_bitreader_peek_16bits(em_lsb_bitreader_t *pBitReader) {
+ if (pBitReader->nDecShifterBitCount < 16) {
+ if (pBitReader->pInBlock < pBitReader->pInBlockEnd) {
+ pBitReader->nDecShifterData |= (((em_lsb_bitreader_shifter_t)(*pBitReader->pInBlock++)) << pBitReader->nDecShifterBitCount);
+ if (pBitReader->pInBlock < pBitReader->pInBlockEnd)
+ pBitReader->nDecShifterData |= (((em_lsb_bitreader_shifter_t)(*pBitReader->pInBlock++)) << (pBitReader->nDecShifterBitCount + 8));
+ pBitReader->nDecShifterBitCount += 16;
+ }
+ }
+
+ return pBitReader->nDecShifterData & 0xffff;
+}
+
+/**
+ * Consume variable bit-length value, after reading it with em_lsb_bitreader_peek_16bits()
+ *
+ * @param pBitReader bit reader context
+ * @param nBits size of value to consume, in bits
+ */
+static inline void em_lsb_bitreader_consume_bits(em_lsb_bitreader_t *pBitReader, const int nBits) {
+ pBitReader->nDecShifterData >>= nBits;
+ pBitReader->nDecShifterBitCount -= nBits;
+}
+
+/**
+ * Re-align bitstream on a byte
+ *
+ * @param pBitReader bit reader context
+ */
+static int em_lsb_bitreader_byte_align(em_lsb_bitreader_t *pBitReader) {
+ /* Align on byte */
+ while (pBitReader->nDecShifterBitCount >= 8) {
+ /* Rewind - the bit reader can load more than 8 bits at a time */
+ pBitReader->nDecShifterBitCount -= 8;
+ pBitReader->pInBlock--;
+ if (pBitReader->pInBlock < pBitReader->pInBlockStart) return -1;
+ }
+
+ pBitReader->nDecShifterBitCount = 0;
+ pBitReader->nDecShifterData = 0;
+ return 0;
+}
+
+/*-- Huffman decoder for a LSB bitstream --*/
+
+/** Maximum number of symbols that can be read by the huffman decoder */
+#define MAX_SYMBOLS 288
+
+/** Number of symbols used to decode variable code lengths */
+#define NCODELENSYMS 19
+
+/** Number of most significant huffman codeword bits that are used to skip the initial code length finding steps */
+#define NFASTSYMBOLBITS 10
+
+/** Huffman decoding context */
+typedef struct {
+ unsigned int nFastSymbol[1 << NFASTSYMBOLBITS];
+ unsigned int nStartIndex[16]; /* One per code bit length */
+ unsigned int nSymbols;
+ int nNumSorted;
+ int nStartingPos[16];
+} em_lsb_huffman_decoder_t;
+
+/**
+ * Prepare huffman tables
+ *
+ * @param pDecoder decoding context
+ * @param pRevSymbolTable array of 2 * nSymbols entries for storing the reverse lookup table
+ * @param pCodeLength codeword lengths table
+ *
+ * @return 0 for success, -1 for failure
+ */
+static int em_lsb_huffman_decoder_prepare_table(em_lsb_huffman_decoder_t *pDecoder, unsigned int *pRevSymbolTable, const int nReadSymbols, const int nSymbols, const unsigned char *pCodeLength) {
+ int nNumSymbolsPerLen[16];
+ int i;
+
+ if (nReadSymbols < 0 || nReadSymbols > MAX_SYMBOLS || nSymbols < 0 || nSymbols > MAX_SYMBOLS || nReadSymbols > nSymbols)
+ return -1;
+ pDecoder->nSymbols = nSymbols;
+
+ /* Calculate starting positions of symbols for each code length, so we don't have to sort them */
+
+ for (i = 0; i < 16; i++)
+ nNumSymbolsPerLen[i] = 0;
+ for (i = 0; i < nReadSymbols; i++) {
+ if (pCodeLength[i] >= 16) return -1;
+ nNumSymbolsPerLen[pCodeLength[i]]++;
+ }
+
+ pDecoder->nStartingPos[0] = 0;
+ pDecoder->nNumSorted = 0;
+ for (i = 1; i < 16; i++) {
+ pDecoder->nStartingPos[i] = pDecoder->nNumSorted;
+ pDecoder->nNumSorted += nNumSymbolsPerLen[i];
+ }
+
+ /* Assign symbols for any non-zero lengths, auto sorted by increasing code length */
+
+ for (i = 0; i < nSymbols; i++)
+ pRevSymbolTable[i] = -1;
+
+ for (i = 0; i < nReadSymbols; i++) {
+ if (pCodeLength[i]) {
+ pRevSymbolTable[pDecoder->nStartingPos[pCodeLength[i]]++] = i;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Finalize huffman codewords for decoding
+ *
+ * @param pDecoder decoding context
+ * @param pRevSymbolTable array of 2 * nSymbols entries that contains the reverse lookup table
+ *
+ * @return 0 for success, -1 for failure
+ */
+static int em_lsb_huffman_decoder_finalize_table(em_lsb_huffman_decoder_t *pDecoder, unsigned int *pRevSymbolTable) {
+ const int nSymbols = pDecoder->nSymbols;
+ unsigned int nCanonicalCodeWord = 0;
+ unsigned int *nRevCodeLengthTable = pRevSymbolTable + nSymbols;
+ int nCanonicalLength = 1;
+ int i;
+
+ /* Re-create canonical huffman codewords and create left-justified words for em_lsb_huffman_decoder_read_value() */
+
+ for (i = 0; i < (1 << NFASTSYMBOLBITS); i++)
+ pDecoder->nFastSymbol[i] = 0;
+ for (i = 0; i < 16; i++)
+ pDecoder->nStartIndex[i] = 0;
+
+ i = 0;
+ while (i < pDecoder->nNumSorted) {
+ if (nCanonicalLength >= 16) return -1;
+ pDecoder->nStartIndex[nCanonicalLength] = i - nCanonicalCodeWord;
+
+ while (i < pDecoder->nStartingPos[nCanonicalLength]) {
+ /* Write canonical order -> codeword mapping */
+ if (i >= nSymbols) return -1;
+ nRevCodeLengthTable[i] = nCanonicalLength;
+
+ /* Check for malformed table */
+ if (nCanonicalCodeWord >= (1U << nCanonicalLength)) return -1;
+
+ /* Write accelerated symbol value + codeword len for the (upside down) top NFASTSYMBOLBITS bits of the codeword, at all bit positions */
+ if (nCanonicalLength <= NFASTSYMBOLBITS) {
+ unsigned int nRevWord;
+
+ /* Get upside down codeword (branchless method by Eric Biggers) */
+ nRevWord = ((nCanonicalCodeWord & 0x5555) << 1) | ((nCanonicalCodeWord & 0xaaaa) >> 1);
+ nRevWord = ((nRevWord & 0x3333) << 2) | ((nRevWord & 0xcccc) >> 2);
+ nRevWord = ((nRevWord & 0x0f0f) << 4) | ((nRevWord & 0xf0f0) >> 4);
+ nRevWord = ((nRevWord & 0x00ff) << 8) | ((nRevWord & 0xff00) >> 8);
+ nRevWord = nRevWord >> (16 - nCanonicalLength);
+
+ int nSlots = 1 << (NFASTSYMBOLBITS - nCanonicalLength);
+ while (nSlots) {
+ pDecoder->nFastSymbol[nRevWord] = (pRevSymbolTable[i] & 0xffffff) | (nCanonicalLength << 24);
+ nRevWord += (1 << nCanonicalLength);
+ nSlots--;
+ }
+ }
+
+ i++;
+ nCanonicalCodeWord++;
+ }
+ nCanonicalLength++;
+ nCanonicalCodeWord <<= 1;
+ }
+
+ while (i < nSymbols) {
+ pRevSymbolTable[i] = -1;
+ nRevCodeLengthTable[i++] = 0;
+ }
+
+ return 0;
+}
+
+/**
+ * Decode next symbol
+ *
+ * @param pDecoder decoding context
+ * @param pRevSymbolTable reverse lookup table
+ * @param pBitReader bit reader context
+ *
+ * @return symbol, or -1 for error
+ */
+static inline unsigned int em_lsb_huffman_decoder_read_value(em_lsb_huffman_decoder_t *pDecoder, const unsigned int *pRevSymbolTable, em_lsb_bitreader_t *pBitReader) {
+ unsigned int nStream = em_lsb_bitreader_peek_16bits(pBitReader);
+ unsigned int nFastSymAndBits = pDecoder->nFastSymbol[nStream & ((1 << NFASTSYMBOLBITS) - 1)];
+ if (nFastSymAndBits) {
+ /* Fast path: the symbol len is <= NFASTSYMBOLBITS, we have a symbol and bit length for the (upside-down) MSB bits */
+ em_lsb_bitreader_consume_bits(pBitReader, nFastSymAndBits >> 24);
+ return nFastSymAndBits & 0xffffff;
+ }
+
+ /* The symbol len is larger than NFASTSYMBOLBITS, decode using the slower path. By definition, the more frequent symbols are shorter and in the fast path. */
+
+ const unsigned int *nRevCodeLengthTable = pRevSymbolTable + pDecoder->nSymbols;
+ unsigned int nCodeWord = 0;
+ int nBits = 1;
+
+ do {
+ nCodeWord |= (nStream & 1);
+
+ unsigned int nTableIndex = pDecoder->nStartIndex[nBits] + nCodeWord;
+ if (nTableIndex < pDecoder->nSymbols) {
+ if (nBits == nRevCodeLengthTable[nTableIndex]) {
+ em_lsb_bitreader_consume_bits(pBitReader, nBits);
+ return pRevSymbolTable[nTableIndex];
+ }
+ }
+
+ nCodeWord <<= 1;
+ nStream >>= 1;
+ nBits++;
+ } while (nBits < 16);
+ return -1;
+}
+
+/**
+ * Read fixed bit size code lengths
+ *
+ * @param nLenBits number of bits per code length
+ * @param nReadSymbols number of symbols actually read
+ * @param nSymbols number of symbols to build codes for
+ * @param pCodeLength output code lengths table
+ * @param pBitReader bit reader context
+ *
+ * @return 0 for success, -1 for failure
+ */
+static int em_lsb_huffman_decoder_read_raw_lengths(const int nLenBits, const int nReadSymbols, const int nSymbols, unsigned char *pCodeLength, em_lsb_bitreader_t *pBitReader) {
+ static const unsigned char nCodeLenSymIndex[NCODELENSYMS] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; /* Order in which code lengths are stored, as per the zlib specification */
+ int i;
+
+ if (nReadSymbols < 0 || nReadSymbols > MAX_SYMBOLS || nSymbols < 0 || nSymbols > MAX_SYMBOLS || nReadSymbols > nSymbols)
+ return -1;
+
+ i = 0;
+ while (i < nReadSymbols) {
+ unsigned int nLength = em_lsb_bitreader_get_bits(pBitReader, nLenBits);
+ if (nLength == -1) return -1;
+
+ pCodeLength[nCodeLenSymIndex[i++]] = nLength;
+ }
+
+ while (i < nSymbols) {
+ pCodeLength[nCodeLenSymIndex[i++]] = 0;
+ }
+
+ return 0;
+}
+
+/**
+ * Read huffman-encoded code lengths
+ *
+ * @param pTablesDecoder decoding context for code lengths
+ * @param pTablesRevSymbolTable reverse lookup table for code lengths
+ * @param nReadSymbols number of symbols actually read
+ * @param nSymbols number of symbols to build codes for
+ * @param pCodeLength output code lengths table
+ * @param pBitReader bit reader context
+ *
+ * @return 0 for success, -1 for failure
+ */
+static int em_lsb_huffman_decoder_read_var_lengths(em_lsb_huffman_decoder_t *pTablesDecoder, const unsigned int *pTablesRevSymbolTable,
+ const int nReadSymbols, const int nSymbols, unsigned char *pCodeLength, em_lsb_bitreader_t *pBitReader) {
+ int i;
+
+ if (nReadSymbols < 0 || nSymbols < 0 || nReadSymbols > nSymbols)
+ return -1;
+
+ i = 0;
+ unsigned int nPrevLength = 0;
+
+ while (i < nReadSymbols) {
+ unsigned int nLength = em_lsb_huffman_decoder_read_value(pTablesDecoder, pTablesRevSymbolTable, pBitReader);
+ if (nLength == -1) return -1;
+
+ if (nLength < 16) {
+ nPrevLength = nLength;
+ pCodeLength[i++] = nPrevLength;
+ }
+ else {
+ unsigned int nRunLen = 0;
+
+ if (nLength == 16) {
+ int nExtraRunLen = em_lsb_bitreader_get_bits(pBitReader, 2);
+ if (nExtraRunLen == -1) return -1;
+ nRunLen = 3 + nExtraRunLen;
+ }
+ else if (nLength == 17) {
+ int nExtraRunLen = em_lsb_bitreader_get_bits(pBitReader, 3);
+ if (nExtraRunLen == -1) return -1;
+ nPrevLength = 0;
+ nRunLen = 3 + nExtraRunLen;
+ }
+ else if (nLength == 18) {
+ int nExtraRunLen = em_lsb_bitreader_get_bits(pBitReader, 7);
+ if (nExtraRunLen == -1) return -1;
+ nPrevLength = 0;
+ nRunLen = 11 + nExtraRunLen;
+ }
+
+ while (nRunLen && i < nReadSymbols) {
+ pCodeLength[i++] = nPrevLength;
+ nRunLen--;
+ }
+ }
+ }
+
+ while (i < nSymbols)
+ pCodeLength[i++] = 0;
+ return 0;
+}
+
+/*-- zlib stored blocks copier --*/
+
+static size_t em_inflate_copy_stored(em_lsb_bitreader_t *pBitReader, unsigned char *pOutData, size_t nOutDataOffset, size_t nBlockMaxSize) {
+ /* Align on byte */
+ if (em_lsb_bitreader_byte_align(pBitReader) < 0)
+ return -1;
+
+ if ((pBitReader->pInBlock + 4) > pBitReader->pInBlockEnd) return -1;
+
+ /* Read block length, and its two's complement verification value */
+ unsigned short nStoredLen = ((unsigned short)pBitReader->pInBlock[0]) | (((unsigned short)pBitReader->pInBlock[1]) << 8);
+ pBitReader->pInBlock += 2;
+
+ unsigned short nNegStoredLen = ((unsigned short)pBitReader->pInBlock[0]) | (((unsigned short)pBitReader->pInBlock[1]) << 8);
+ pBitReader->pInBlock += 2;
+
+ /* Make sure that the len and the two's complement match */
+ if (nStoredLen != ((~nNegStoredLen) & 0xffff)) return -1;
+
+ /* Make sure there is room */
+ if (nStoredLen > nBlockMaxSize) return -1;
+
+ /* Copy stored data */
+ memcpy(pOutData + nOutDataOffset, pBitReader->pInBlock, nStoredLen);
+ pBitReader->pInBlock += nStoredLen;
+
+ return (size_t)nStoredLen;
+}
+
+/*-- zlib static and dynamic blocks inflater --*/
+
+#define NCODELENBITS 3
+#define NLITERALSYMS 288
+#define NEODMARKERSYM 256
+#define NMATCHLENSYMSTART 257
+#define NMATCHLENSYMS 29
+#define NOFFSETSYMS 32
+#define MIN_MATCH_SIZE 3
+#define MATCHLEN_PAIR(__base,__dispbits) ((__base) | ((__dispbits) << 16) | 0x8000)
+#define OFFSET_PAIR(__base,__dispbits) ((__base) | ((__dispbits) << 16))
+
+/** Base value and number of extra displacement bits for each match length codeword */
+static const unsigned int em_inflate_matchlen_code[NMATCHLENSYMS] = {
+ MATCHLEN_PAIR(MIN_MATCH_SIZE + 0, 0), MATCHLEN_PAIR(MIN_MATCH_SIZE + 1, 0), MATCHLEN_PAIR(MIN_MATCH_SIZE + 2, 0), MATCHLEN_PAIR(MIN_MATCH_SIZE + 3, 0), MATCHLEN_PAIR(MIN_MATCH_SIZE + 4, 0),
+ MATCHLEN_PAIR(MIN_MATCH_SIZE + 5, 0), MATCHLEN_PAIR(MIN_MATCH_SIZE + 6, 0), MATCHLEN_PAIR(MIN_MATCH_SIZE + 7, 0), MATCHLEN_PAIR(MIN_MATCH_SIZE + 8, 1), MATCHLEN_PAIR(MIN_MATCH_SIZE + 10, 1),
+ MATCHLEN_PAIR(MIN_MATCH_SIZE + 12, 1), MATCHLEN_PAIR(MIN_MATCH_SIZE + 14, 1), MATCHLEN_PAIR(MIN_MATCH_SIZE + 16, 2), MATCHLEN_PAIR(MIN_MATCH_SIZE + 20, 2), MATCHLEN_PAIR(MIN_MATCH_SIZE + 24, 2),
+ MATCHLEN_PAIR(MIN_MATCH_SIZE + 28, 2), MATCHLEN_PAIR(MIN_MATCH_SIZE + 32, 3), MATCHLEN_PAIR(MIN_MATCH_SIZE + 40, 3), MATCHLEN_PAIR(MIN_MATCH_SIZE + 48, 3), MATCHLEN_PAIR(MIN_MATCH_SIZE + 56, 3),
+ MATCHLEN_PAIR(MIN_MATCH_SIZE + 64, 4), MATCHLEN_PAIR(MIN_MATCH_SIZE + 80, 4), MATCHLEN_PAIR(MIN_MATCH_SIZE + 96, 4), MATCHLEN_PAIR(MIN_MATCH_SIZE + 112, 4), MATCHLEN_PAIR(MIN_MATCH_SIZE + 128, 5),
+ MATCHLEN_PAIR(MIN_MATCH_SIZE + 160, 5), MATCHLEN_PAIR(MIN_MATCH_SIZE + 192, 5), MATCHLEN_PAIR(MIN_MATCH_SIZE + 224, 5), MATCHLEN_PAIR(MIN_MATCH_SIZE + 255, 0),
+};
+
+/** Base value and number of extra displacement bits for each offset codeword */
+static const unsigned int em_inflate_offset_code[NOFFSETSYMS] = {
+ OFFSET_PAIR(1, 0), OFFSET_PAIR(2, 0), OFFSET_PAIR(3, 0), OFFSET_PAIR(4, 0), OFFSET_PAIR(5, 1), OFFSET_PAIR(7, 1), OFFSET_PAIR(9, 2), OFFSET_PAIR(13, 2), OFFSET_PAIR(17, 3), OFFSET_PAIR(25, 3),
+ OFFSET_PAIR(33, 4), OFFSET_PAIR(49, 4), OFFSET_PAIR(65, 5), OFFSET_PAIR(97, 5), OFFSET_PAIR(129, 6), OFFSET_PAIR(193, 6), OFFSET_PAIR(257, 7), OFFSET_PAIR(385, 7), OFFSET_PAIR(513, 8), OFFSET_PAIR(769, 8),
+ OFFSET_PAIR(1025, 9), OFFSET_PAIR(1537, 9), OFFSET_PAIR(2049, 10), OFFSET_PAIR(3073, 10), OFFSET_PAIR(4097, 11), OFFSET_PAIR(6145, 11), OFFSET_PAIR(8193, 12), OFFSET_PAIR(12289, 12), OFFSET_PAIR(16385, 13), OFFSET_PAIR(24577, 13),
+};
+
+/**
+ * Decompress one data block
+ *
+ * @param pInBlock pointer to compressed data
+ * @param nDynamicBlock non-zero for a dynamic huffman tables block, zero for a static huffman tables block
+ * @param nInBlockSize size of compressed data, in bytes
+ * @param pOutData pointer to output decompression buffer (previously decompressed bytes + room for decompressing this block)
+ * @param nOutDataOffset starting index of where to store decompressed bytes in output buffer (and size of previously decompressed bytes)
+ * @param nBlockMaxSize total size of output decompression buffer, in bytes
+ *
+ * @return size of decompressed data in bytes, or -1 for error
+ */
+static size_t em_inflate_decompress_block(em_lsb_bitreader_t *pBitReader, int nDynamicBlock, unsigned char *pOutData, size_t nOutDataOffset, size_t nBlockMaxSize) {
+ em_lsb_huffman_decoder_t literalsDecoder;
+ em_lsb_huffman_decoder_t offsetDecoder;
+ unsigned int nLiteralsRevSymbolTable[NLITERALSYMS * 2];
+ unsigned int nOffsetRevSymbolTable[NOFFSETSYMS * 2];
+ int i;
+
+ if (nDynamicBlock) {
+ em_lsb_huffman_decoder_t tablesDecoder;
+ unsigned char nCodeLength[NLITERALSYMS + NOFFSETSYMS];
+ unsigned int nTablesRevSymbolTable[NCODELENSYMS * 2];
+
+ /* Read the encoded number of literals/match len symbols, offset symbols, and code length symbols */
+ unsigned int nLiteralSyms = em_lsb_bitreader_get_bits(pBitReader, 5);
+ if (nLiteralSyms == -1) return -1;
+ nLiteralSyms += 257;
+ if (nLiteralSyms > NLITERALSYMS) return -1;
+
+ unsigned int nOffsetSyms = em_lsb_bitreader_get_bits(pBitReader, 5);
+ if (nOffsetSyms == -1) return -1;
+ nOffsetSyms += 1;
+ if (nOffsetSyms > NOFFSETSYMS) return -1;
+
+ unsigned int nCodeLenSyms = em_lsb_bitreader_get_bits(pBitReader, 4);
+ if (nCodeLenSyms == -1) return -1;
+ nCodeLenSyms += 4;
+ if (nCodeLenSyms > NCODELENSYMS) return -1;
+
+ /* Read code lengths table */
+ if (em_lsb_huffman_decoder_read_raw_lengths(NCODELENBITS /* code length bits */, nCodeLenSyms /* symbols */, NCODELENSYMS, nCodeLength, pBitReader) < 0)
+ return -1;
+ if (em_lsb_huffman_decoder_prepare_table(&tablesDecoder, nTablesRevSymbolTable, NCODELENSYMS, NCODELENSYMS, nCodeLength) < 0)
+ return -1;
+ if (em_lsb_huffman_decoder_finalize_table(&tablesDecoder, nTablesRevSymbolTable) < 0)
+ return -1;
+
+ /* Use code lengths table to read literals/match len and offset tables */
+ if (em_lsb_huffman_decoder_read_var_lengths(&tablesDecoder, nTablesRevSymbolTable, nLiteralSyms + nOffsetSyms /* read symbols */, NLITERALSYMS + NOFFSETSYMS /* total symbols */, nCodeLength, pBitReader) < 0)
+ return -1;
+ if (em_lsb_huffman_decoder_prepare_table(&literalsDecoder, nLiteralsRevSymbolTable, nLiteralSyms, NLITERALSYMS, nCodeLength) < 0)
+ return -1;
+ if (em_lsb_huffman_decoder_prepare_table(&offsetDecoder, nOffsetRevSymbolTable, nOffsetSyms, NOFFSETSYMS, nCodeLength + nLiteralSyms) < 0)
+ return -1;
+ }
+ else {
+ unsigned char nFixedLiteralCodeLen[NLITERALSYMS];
+ unsigned char nFixedOffsetCodeLen[NOFFSETSYMS];
+
+ /* Fixed huffman codes for this block. Build fixed code lengths for literals/match lens and offsets, as per the zlib specification */
+
+ for (i = 0; i < 144; i++)
+ nFixedLiteralCodeLen[i] = 8;
+ for (; i < 256; i++)
+ nFixedLiteralCodeLen[i] = 9;
+ for (; i < 280; i++)
+ nFixedLiteralCodeLen[i] = 7;
+ for (; i < NLITERALSYMS; i++)
+ nFixedLiteralCodeLen[i] = 8;
+
+ for (i = 0; i < NOFFSETSYMS; i++)
+ nFixedOffsetCodeLen[i] = 5;
+
+ if (em_lsb_huffman_decoder_prepare_table(&literalsDecoder, nLiteralsRevSymbolTable, NLITERALSYMS, NLITERALSYMS, nFixedLiteralCodeLen) < 0)
+ return -1;
+ if (em_lsb_huffman_decoder_prepare_table(&offsetDecoder, nOffsetRevSymbolTable, NOFFSETSYMS, NOFFSETSYMS, nFixedOffsetCodeLen) < 0)
+ return -1;
+ }
+
+ /* Replace codewords in the offsets table by the base + extra bit count, save table lookups when decoding */
+ for (i = 0; i < NOFFSETSYMS; i++) {
+ unsigned int n = nOffsetRevSymbolTable[i];
+ if (n < NOFFSETSYMS) {
+ nOffsetRevSymbolTable[i] = em_inflate_offset_code[n];
+ }
+ }
+
+ /* Replace match codewords in the literals/match len table by the base + extra bit count, save table lookups when decoding */
+ for (i = 0; i < NLITERALSYMS; i++) {
+ unsigned int n = nLiteralsRevSymbolTable[i];
+ if (n >= NMATCHLENSYMSTART && n < NLITERALSYMS) {
+ int index = n - NMATCHLENSYMSTART;
+ if (index >= 0 && index < NMATCHLENSYMS) {
+ nLiteralsRevSymbolTable[i] = em_inflate_matchlen_code[index];
+ }
+ else {
+ /* Handle 286 and 287 codes, used for constructing a complete canonical tree, present in static huffman tables but not used */
+ nLiteralsRevSymbolTable[i] = 0;
+ }
+ }
+ }
+
+ /* Finalize huffman tables for decoding, after setting up the bases + extra bits as the symbols */
+ if (em_lsb_huffman_decoder_finalize_table(&literalsDecoder, nLiteralsRevSymbolTable) < 0)
+ return -1;
+ if (em_lsb_huffman_decoder_finalize_table(&offsetDecoder, nOffsetRevSymbolTable) < 0)
+ return -1;
+
+ /* Finally, loop to read all the literals/match len codewords in the block to decompress it */
+
+ unsigned char *pCurOutData = pOutData + nOutDataOffset;
+ const unsigned char *pOutDataEnd = pCurOutData + nBlockMaxSize;
+ const unsigned char *pOutDataFastEnd = pOutDataEnd - 15;
+
+ while (1) {
+ em_lsb_bitreader_refill_32(pBitReader);
+
+ unsigned int nLiteralsCodeword = em_lsb_huffman_decoder_read_value(&literalsDecoder, nLiteralsRevSymbolTable, pBitReader);
+ if (nLiteralsCodeword < 256) {
+ /* 0..255: literal. copy. */
+ if (pCurOutData < pOutDataEnd)
+ *pCurOutData++ = nLiteralsCodeword;
+ else
+ return -1;
+ }
+ else {
+ if (nLiteralsCodeword == NEODMARKERSYM) break; /* EOD marker, all done */
+ if (nLiteralsCodeword == -1) return -1;
+
+ /* 256..284: match. decode match length. */
+
+ unsigned int nMatchLen = em_lsb_bitreader_get_bits(pBitReader, (nLiteralsCodeword >> 16) & 15);
+ if (nMatchLen == -1) return -1;
+
+ nMatchLen += (nLiteralsCodeword & 0x7fff);
+
+ /* Read match offset */
+
+ unsigned int nOffsetCodeword = em_lsb_huffman_decoder_read_value(&offsetDecoder, nOffsetRevSymbolTable, pBitReader);
+ if (nOffsetCodeword == -1) return -1;
+
+ unsigned int nMatchOffset = em_lsb_bitreader_get_bits(pBitReader, (nOffsetCodeword >> 16) & 15);
+ if (nMatchOffset == -1) return -1;
+
+ nMatchOffset += (nOffsetCodeword & 0x7fff);
+
+ /* Copy match */
+
+ const unsigned char *pSrc = pCurOutData - nMatchOffset;
+ if (pSrc >= pOutData) {
+ if (nMatchOffset >= 16 && (pCurOutData + nMatchLen) <= pOutDataFastEnd) {
+ const unsigned char *pCopySrc = pSrc;
+ unsigned char *pCopyDst = pCurOutData;
+ const unsigned char *pCopyEndDst = pCurOutData + nMatchLen;
+
+ do {
+ memcpy(pCopyDst, pCopySrc, 16);
+ pCopySrc += 16;
+ pCopyDst += 16;
+ } while (pCopyDst < pCopyEndDst);
+
+ pCurOutData += nMatchLen;
+ }
+ else {
+ if ((pCurOutData + nMatchLen) > pOutDataEnd) return -1;
+
+ while (nMatchLen--) {
+ *pCurOutData++ = *pSrc++;
+ }
+ }
+ }
+ else
+ return -1;
+ }
+ }
+
+ return (size_t)(pCurOutData - (pOutData + nOutDataOffset));
+}
+
+/*-- zlib adler32 calculation --*/
+
+#ifdef EM_INFLATE_VERIFY_CHECKSUM
+
+/*
+ By Mark Adler - https://github.com/madler/zlib/blob/master/adler32.c
+
+ Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
+ (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
+ */
+
+#define BASE 65521U /* largest prime smaller than 65536 */
+#define NMAX 5552
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+# define MOD(a) a %= BASE
+# define MOD28(a) a %= BASE
+# define MOD63(a) a %= BASE
+
+static unsigned int em_inflate_adler32_z(unsigned int adler, const unsigned char *buf, size_t len) {
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD28(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/*-- gzip crc32 calculation --*/
+
+/**
+By Stephen Brumme - https://create.stephan-brumme.com/crc32/
+
+Unless otherwise noted in a file's first 5 lines, all source code published on http://create.stephan-brumme.com and its sub-pages is licensed similar to the zlib license:
+
+This software is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
+If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+ */
+
+static const unsigned int ema_inflate_Crc32Lookup[4][256] = {
+ {
+ 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,
+ 0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
+ 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,
+ 0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
+ 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,
+ 0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
+ 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,
+ 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
+ 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,
+ 0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
+ 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,
+ 0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
+ 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,
+ 0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
+ 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,
+ 0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
+ 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,
+ 0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
+ 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,
+ 0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
+ 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,
+ 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
+ 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,
+ 0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
+ 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,
+ 0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
+ 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,
+ 0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
+ 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,
+ 0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
+ 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,
+ 0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
+ }
+
+ // beyond this point only relevant for Slicing-by-4, Slicing-by-8 and Slicing-by-16
+ ,{
+ 0x00000000,0x191B3141,0x32366282,0x2B2D53C3,0x646CC504,0x7D77F445,0x565AA786,0x4F4196C7,
+ 0xC8D98A08,0xD1C2BB49,0xFAEFE88A,0xE3F4D9CB,0xACB54F0C,0xB5AE7E4D,0x9E832D8E,0x87981CCF,
+ 0x4AC21251,0x53D92310,0x78F470D3,0x61EF4192,0x2EAED755,0x37B5E614,0x1C98B5D7,0x05838496,
+ 0x821B9859,0x9B00A918,0xB02DFADB,0xA936CB9A,0xE6775D5D,0xFF6C6C1C,0xD4413FDF,0xCD5A0E9E,
+ 0x958424A2,0x8C9F15E3,0xA7B24620,0xBEA97761,0xF1E8E1A6,0xE8F3D0E7,0xC3DE8324,0xDAC5B265,
+ 0x5D5DAEAA,0x44469FEB,0x6F6BCC28,0x7670FD69,0x39316BAE,0x202A5AEF,0x0B07092C,0x121C386D,
+ 0xDF4636F3,0xC65D07B2,0xED705471,0xF46B6530,0xBB2AF3F7,0xA231C2B6,0x891C9175,0x9007A034,
+ 0x179FBCFB,0x0E848DBA,0x25A9DE79,0x3CB2EF38,0x73F379FF,0x6AE848BE,0x41C51B7D,0x58DE2A3C,
+ 0xF0794F05,0xE9627E44,0xC24F2D87,0xDB541CC6,0x94158A01,0x8D0EBB40,0xA623E883,0xBF38D9C2,
+ 0x38A0C50D,0x21BBF44C,0x0A96A78F,0x138D96CE,0x5CCC0009,0x45D73148,0x6EFA628B,0x77E153CA,
+ 0xBABB5D54,0xA3A06C15,0x888D3FD6,0x91960E97,0xDED79850,0xC7CCA911,0xECE1FAD2,0xF5FACB93,
+ 0x7262D75C,0x6B79E61D,0x4054B5DE,0x594F849F,0x160E1258,0x0F152319,0x243870DA,0x3D23419B,
+ 0x65FD6BA7,0x7CE65AE6,0x57CB0925,0x4ED03864,0x0191AEA3,0x188A9FE2,0x33A7CC21,0x2ABCFD60,
+ 0xAD24E1AF,0xB43FD0EE,0x9F12832D,0x8609B26C,0xC94824AB,0xD05315EA,0xFB7E4629,0xE2657768,
+ 0x2F3F79F6,0x362448B7,0x1D091B74,0x04122A35,0x4B53BCF2,0x52488DB3,0x7965DE70,0x607EEF31,
+ 0xE7E6F3FE,0xFEFDC2BF,0xD5D0917C,0xCCCBA03D,0x838A36FA,0x9A9107BB,0xB1BC5478,0xA8A76539,
+ 0x3B83984B,0x2298A90A,0x09B5FAC9,0x10AECB88,0x5FEF5D4F,0x46F46C0E,0x6DD93FCD,0x74C20E8C,
+ 0xF35A1243,0xEA412302,0xC16C70C1,0xD8774180,0x9736D747,0x8E2DE606,0xA500B5C5,0xBC1B8484,
+ 0x71418A1A,0x685ABB5B,0x4377E898,0x5A6CD9D9,0x152D4F1E,0x0C367E5F,0x271B2D9C,0x3E001CDD,
+ 0xB9980012,0xA0833153,0x8BAE6290,0x92B553D1,0xDDF4C516,0xC4EFF457,0xEFC2A794,0xF6D996D5,
+ 0xAE07BCE9,0xB71C8DA8,0x9C31DE6B,0x852AEF2A,0xCA6B79ED,0xD37048AC,0xF85D1B6F,0xE1462A2E,
+ 0x66DE36E1,0x7FC507A0,0x54E85463,0x4DF36522,0x02B2F3E5,0x1BA9C2A4,0x30849167,0x299FA026,
+ 0xE4C5AEB8,0xFDDE9FF9,0xD6F3CC3A,0xCFE8FD7B,0x80A96BBC,0x99B25AFD,0xB29F093E,0xAB84387F,
+ 0x2C1C24B0,0x350715F1,0x1E2A4632,0x07317773,0x4870E1B4,0x516BD0F5,0x7A468336,0x635DB277,
+ 0xCBFAD74E,0xD2E1E60F,0xF9CCB5CC,0xE0D7848D,0xAF96124A,0xB68D230B,0x9DA070C8,0x84BB4189,
+ 0x03235D46,0x1A386C07,0x31153FC4,0x280E0E85,0x674F9842,0x7E54A903,0x5579FAC0,0x4C62CB81,
+ 0x8138C51F,0x9823F45E,0xB30EA79D,0xAA1596DC,0xE554001B,0xFC4F315A,0xD7626299,0xCE7953D8,
+ 0x49E14F17,0x50FA7E56,0x7BD72D95,0x62CC1CD4,0x2D8D8A13,0x3496BB52,0x1FBBE891,0x06A0D9D0,
+ 0x5E7EF3EC,0x4765C2AD,0x6C48916E,0x7553A02F,0x3A1236E8,0x230907A9,0x0824546A,0x113F652B,
+ 0x96A779E4,0x8FBC48A5,0xA4911B66,0xBD8A2A27,0xF2CBBCE0,0xEBD08DA1,0xC0FDDE62,0xD9E6EF23,
+ 0x14BCE1BD,0x0DA7D0FC,0x268A833F,0x3F91B27E,0x70D024B9,0x69CB15F8,0x42E6463B,0x5BFD777A,
+ 0xDC656BB5,0xC57E5AF4,0xEE530937,0xF7483876,0xB809AEB1,0xA1129FF0,0x8A3FCC33,0x9324FD72,
+ },
+
+ {
+ 0x00000000,0x01C26A37,0x0384D46E,0x0246BE59,0x0709A8DC,0x06CBC2EB,0x048D7CB2,0x054F1685,
+ 0x0E1351B8,0x0FD13B8F,0x0D9785D6,0x0C55EFE1,0x091AF964,0x08D89353,0x0A9E2D0A,0x0B5C473D,
+ 0x1C26A370,0x1DE4C947,0x1FA2771E,0x1E601D29,0x1B2F0BAC,0x1AED619B,0x18ABDFC2,0x1969B5F5,
+ 0x1235F2C8,0x13F798FF,0x11B126A6,0x10734C91,0x153C5A14,0x14FE3023,0x16B88E7A,0x177AE44D,
+ 0x384D46E0,0x398F2CD7,0x3BC9928E,0x3A0BF8B9,0x3F44EE3C,0x3E86840B,0x3CC03A52,0x3D025065,
+ 0x365E1758,0x379C7D6F,0x35DAC336,0x3418A901,0x3157BF84,0x3095D5B3,0x32D36BEA,0x331101DD,
+ 0x246BE590,0x25A98FA7,0x27EF31FE,0x262D5BC9,0x23624D4C,0x22A0277B,0x20E69922,0x2124F315,
+ 0x2A78B428,0x2BBADE1F,0x29FC6046,0x283E0A71,0x2D711CF4,0x2CB376C3,0x2EF5C89A,0x2F37A2AD,
+ 0x709A8DC0,0x7158E7F7,0x731E59AE,0x72DC3399,0x7793251C,0x76514F2B,0x7417F172,0x75D59B45,
+ 0x7E89DC78,0x7F4BB64F,0x7D0D0816,0x7CCF6221,0x798074A4,0x78421E93,0x7A04A0CA,0x7BC6CAFD,
+ 0x6CBC2EB0,0x6D7E4487,0x6F38FADE,0x6EFA90E9,0x6BB5866C,0x6A77EC5B,0x68315202,0x69F33835,
+ 0x62AF7F08,0x636D153F,0x612BAB66,0x60E9C151,0x65A6D7D4,0x6464BDE3,0x662203BA,0x67E0698D,
+ 0x48D7CB20,0x4915A117,0x4B531F4E,0x4A917579,0x4FDE63FC,0x4E1C09CB,0x4C5AB792,0x4D98DDA5,
+ 0x46C49A98,0x4706F0AF,0x45404EF6,0x448224C1,0x41CD3244,0x400F5873,0x4249E62A,0x438B8C1D,
+ 0x54F16850,0x55330267,0x5775BC3E,0x56B7D609,0x53F8C08C,0x523AAABB,0x507C14E2,0x51BE7ED5,
+ 0x5AE239E8,0x5B2053DF,0x5966ED86,0x58A487B1,0x5DEB9134,0x5C29FB03,0x5E6F455A,0x5FAD2F6D,
+ 0xE1351B80,0xE0F771B7,0xE2B1CFEE,0xE373A5D9,0xE63CB35C,0xE7FED96B,0xE5B86732,0xE47A0D05,
+ 0xEF264A38,0xEEE4200F,0xECA29E56,0xED60F461,0xE82FE2E4,0xE9ED88D3,0xEBAB368A,0xEA695CBD,
+ 0xFD13B8F0,0xFCD1D2C7,0xFE976C9E,0xFF5506A9,0xFA1A102C,0xFBD87A1B,0xF99EC442,0xF85CAE75,
+ 0xF300E948,0xF2C2837F,0xF0843D26,0xF1465711,0xF4094194,0xF5CB2BA3,0xF78D95FA,0xF64FFFCD,
+ 0xD9785D60,0xD8BA3757,0xDAFC890E,0xDB3EE339,0xDE71F5BC,0xDFB39F8B,0xDDF521D2,0xDC374BE5,
+ 0xD76B0CD8,0xD6A966EF,0xD4EFD8B6,0xD52DB281,0xD062A404,0xD1A0CE33,0xD3E6706A,0xD2241A5D,
+ 0xC55EFE10,0xC49C9427,0xC6DA2A7E,0xC7184049,0xC25756CC,0xC3953CFB,0xC1D382A2,0xC011E895,
+ 0xCB4DAFA8,0xCA8FC59F,0xC8C97BC6,0xC90B11F1,0xCC440774,0xCD866D43,0xCFC0D31A,0xCE02B92D,
+ 0x91AF9640,0x906DFC77,0x922B422E,0x93E92819,0x96A63E9C,0x976454AB,0x9522EAF2,0x94E080C5,
+ 0x9FBCC7F8,0x9E7EADCF,0x9C381396,0x9DFA79A1,0x98B56F24,0x99770513,0x9B31BB4A,0x9AF3D17D,
+ 0x8D893530,0x8C4B5F07,0x8E0DE15E,0x8FCF8B69,0x8A809DEC,0x8B42F7DB,0x89044982,0x88C623B5,
+ 0x839A6488,0x82580EBF,0x801EB0E6,0x81DCDAD1,0x8493CC54,0x8551A663,0x8717183A,0x86D5720D,
+ 0xA9E2D0A0,0xA820BA97,0xAA6604CE,0xABA46EF9,0xAEEB787C,0xAF29124B,0xAD6FAC12,0xACADC625,
+ 0xA7F18118,0xA633EB2F,0xA4755576,0xA5B73F41,0xA0F829C4,0xA13A43F3,0xA37CFDAA,0xA2BE979D,
+ 0xB5C473D0,0xB40619E7,0xB640A7BE,0xB782CD89,0xB2CDDB0C,0xB30FB13B,0xB1490F62,0xB08B6555,
+ 0xBBD72268,0xBA15485F,0xB853F606,0xB9919C31,0xBCDE8AB4,0xBD1CE083,0xBF5A5EDA,0xBE9834ED,
+ },
+
+ {
+ 0x00000000,0xB8BC6765,0xAA09C88B,0x12B5AFEE,0x8F629757,0x37DEF032,0x256B5FDC,0x9DD738B9,
+ 0xC5B428EF,0x7D084F8A,0x6FBDE064,0xD7018701,0x4AD6BFB8,0xF26AD8DD,0xE0DF7733,0x58631056,
+ 0x5019579F,0xE8A530FA,0xFA109F14,0x42ACF871,0xDF7BC0C8,0x67C7A7AD,0x75720843,0xCDCE6F26,
+ 0x95AD7F70,0x2D111815,0x3FA4B7FB,0x8718D09E,0x1ACFE827,0xA2738F42,0xB0C620AC,0x087A47C9,
+ 0xA032AF3E,0x188EC85B,0x0A3B67B5,0xB28700D0,0x2F503869,0x97EC5F0C,0x8559F0E2,0x3DE59787,
+ 0x658687D1,0xDD3AE0B4,0xCF8F4F5A,0x7733283F,0xEAE41086,0x525877E3,0x40EDD80D,0xF851BF68,
+ 0xF02BF8A1,0x48979FC4,0x5A22302A,0xE29E574F,0x7F496FF6,0xC7F50893,0xD540A77D,0x6DFCC018,
+ 0x359FD04E,0x8D23B72B,0x9F9618C5,0x272A7FA0,0xBAFD4719,0x0241207C,0x10F48F92,0xA848E8F7,
+ 0x9B14583D,0x23A83F58,0x311D90B6,0x89A1F7D3,0x1476CF6A,0xACCAA80F,0xBE7F07E1,0x06C36084,
+ 0x5EA070D2,0xE61C17B7,0xF4A9B859,0x4C15DF3C,0xD1C2E785,0x697E80E0,0x7BCB2F0E,0xC377486B,
+ 0xCB0D0FA2,0x73B168C7,0x6104C729,0xD9B8A04C,0x446F98F5,0xFCD3FF90,0xEE66507E,0x56DA371B,
+ 0x0EB9274D,0xB6054028,0xA4B0EFC6,0x1C0C88A3,0x81DBB01A,0x3967D77F,0x2BD27891,0x936E1FF4,
+ 0x3B26F703,0x839A9066,0x912F3F88,0x299358ED,0xB4446054,0x0CF80731,0x1E4DA8DF,0xA6F1CFBA,
+ 0xFE92DFEC,0x462EB889,0x549B1767,0xEC277002,0x71F048BB,0xC94C2FDE,0xDBF98030,0x6345E755,
+ 0x6B3FA09C,0xD383C7F9,0xC1366817,0x798A0F72,0xE45D37CB,0x5CE150AE,0x4E54FF40,0xF6E89825,
+ 0xAE8B8873,0x1637EF16,0x048240F8,0xBC3E279D,0x21E91F24,0x99557841,0x8BE0D7AF,0x335CB0CA,
+ 0xED59B63B,0x55E5D15E,0x47507EB0,0xFFEC19D5,0x623B216C,0xDA874609,0xC832E9E7,0x708E8E82,
+ 0x28ED9ED4,0x9051F9B1,0x82E4565F,0x3A58313A,0xA78F0983,0x1F336EE6,0x0D86C108,0xB53AA66D,
+ 0xBD40E1A4,0x05FC86C1,0x1749292F,0xAFF54E4A,0x322276F3,0x8A9E1196,0x982BBE78,0x2097D91D,
+ 0x78F4C94B,0xC048AE2E,0xD2FD01C0,0x6A4166A5,0xF7965E1C,0x4F2A3979,0x5D9F9697,0xE523F1F2,
+ 0x4D6B1905,0xF5D77E60,0xE762D18E,0x5FDEB6EB,0xC2098E52,0x7AB5E937,0x680046D9,0xD0BC21BC,
+ 0x88DF31EA,0x3063568F,0x22D6F961,0x9A6A9E04,0x07BDA6BD,0xBF01C1D8,0xADB46E36,0x15080953,
+ 0x1D724E9A,0xA5CE29FF,0xB77B8611,0x0FC7E174,0x9210D9CD,0x2AACBEA8,0x38191146,0x80A57623,
+ 0xD8C66675,0x607A0110,0x72CFAEFE,0xCA73C99B,0x57A4F122,0xEF189647,0xFDAD39A9,0x45115ECC,
+ 0x764DEE06,0xCEF18963,0xDC44268D,0x64F841E8,0xF92F7951,0x41931E34,0x5326B1DA,0xEB9AD6BF,
+ 0xB3F9C6E9,0x0B45A18C,0x19F00E62,0xA14C6907,0x3C9B51BE,0x842736DB,0x96929935,0x2E2EFE50,
+ 0x2654B999,0x9EE8DEFC,0x8C5D7112,0x34E11677,0xA9362ECE,0x118A49AB,0x033FE645,0xBB838120,
+ 0xE3E09176,0x5B5CF613,0x49E959FD,0xF1553E98,0x6C820621,0xD43E6144,0xC68BCEAA,0x7E37A9CF,
+ 0xD67F4138,0x6EC3265D,0x7C7689B3,0xC4CAEED6,0x591DD66F,0xE1A1B10A,0xF3141EE4,0x4BA87981,
+ 0x13CB69D7,0xAB770EB2,0xB9C2A15C,0x017EC639,0x9CA9FE80,0x241599E5,0x36A0360B,0x8E1C516E,
+ 0x866616A7,0x3EDA71C2,0x2C6FDE2C,0x94D3B949,0x090481F0,0xB1B8E695,0xA30D497B,0x1BB12E1E,
+ 0x43D23E48,0xFB6E592D,0xE9DBF6C3,0x516791A6,0xCCB0A91F,0x740CCE7A,0x66B96194,0xDE0506F1,
+ }
+};
+
+// define endianess and some integer data types
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#elif defined(__APPLE__)
+#include <sys/param.h>
+#define __BYTE_ORDER __DARWIN_BYTE_ORDER
+#else
+ // defines __BYTE_ORDER as __LITTLE_ENDIAN or __BIG_ENDIAN
+#include <sys/param.h>
+#endif
+
+/// swap endianess
+static inline unsigned int em_inflate_crc32_swap(unsigned int x) {
+#if defined(__GNUC__) || defined(__clang__)
+ return __builtin_bswap32(x);
+#else
+ return (x >> 24) |
+ ((x >> 8) & 0x0000FF00) |
+ ((x << 8) & 0x00FF0000) |
+ (x << 24);
+#endif
+}
+
+static unsigned int em_inflate_crc32_4bytes(const void* data, size_t length, unsigned int previousCrc32) {
+ unsigned int crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF
+ const unsigned int* current = (const unsigned int*)data;
+
+ // process four bytes at once (Slicing-by-4)
+ while (length >= 4)
+ {
+#if __BYTE_ORDER == __BIG_ENDIAN
+ unsigned int one = *current++ ^ em_inflate_crc32_swap(crc);
+ crc = ema_inflate_Crc32Lookup[0][one & 0xFF] ^
+ ema_inflate_Crc32Lookup[1][(one >> 8) & 0xFF] ^
+ ema_inflate_Crc32Lookup[2][(one >> 16) & 0xFF] ^
+ ema_inflate_Crc32Lookup[3][(one >> 24) & 0xFF];
+#else
+ unsigned int one = *current++ ^ crc;
+ crc = ema_inflate_Crc32Lookup[0][(one >> 24) & 0xFF] ^
+ ema_inflate_Crc32Lookup[1][(one >> 16) & 0xFF] ^
+ ema_inflate_Crc32Lookup[2][(one >> 8) & 0xFF] ^
+ ema_inflate_Crc32Lookup[3][one & 0xFF];
+#endif
+
+ length -= 4;
+ }
+
+ const unsigned char* currentChar = (const unsigned char*)current;
+ // remaining 1 to 3 bytes (standard algorithm)
+ while (length-- != 0)
+ crc = (crc >> 8) ^ ema_inflate_Crc32Lookup[0][(crc & 0xFF) ^ *currentChar++];
+
+ return ~crc; // same as crc ^ 0xFFFFFFFF
+}
+
+#endif /* EM_INFLATE_VERIFY_CHECKSUM */
+
+/*-- Top level zlib stream inflater --*/
+
+/* What type of checksum to verify, depending on the stream */
+typedef enum { EM_INFLATE_CHECKSUM_NONE = 0, EM_INFLATE_CHECKSUM_GZIP, EM_INFLATE_CHECKSUM_ZLIB } em_inflate_checksum_type_t;
+
+/**
+ * Inflate gzip or zlib data
+ *
+ * @param pCompressedData pointer to start of zlib data
+ * @param nCompressedDataSize size of zlib data, in bytes
+ * @param pOutData pointer to start of decompression buffer
+ * @param nMaxOutDataSize maximum size of decompression buffer, in bytes
+ *
+ * @return number of bytes decompressed, or -1 in case of an error
+ */
+size_t em_inflate(const void *pCompressedData, size_t nCompressedDataSize, unsigned char *pOutData, size_t nMaxOutDataSize) {
+ const unsigned char *pCurCompressedData = (const unsigned char *)pCompressedData;
+ const unsigned char *pEndCompressedData = pCurCompressedData + nCompressedDataSize;
+ em_lsb_bitreader_t bitReader;
+ unsigned int nIsFinalBlock;
+ size_t nCurOutOffset;
+ em_inflate_checksum_type_t nCheckSumType = EM_INFLATE_CHECKSUM_NONE;
+ unsigned long nCheckSum = 0;
+
+ if ((pCurCompressedData + 2) > pEndCompressedData) return -1;
+
+ /* Check header */
+ if (pCurCompressedData[0] == 0x1f && pCurCompressedData[1] == 0x8b) {
+ /* gzip wrapper */
+ pCurCompressedData += 2;
+ if ((pCurCompressedData + 8) > pEndCompressedData || pCurCompressedData[0] != 0x08 /* deflate */)
+ return -1;
+ pCurCompressedData++;
+
+ /* Read flags and skip over the rest of the header */
+ unsigned char flags = *pCurCompressedData++;
+ pCurCompressedData += 6;
+
+ if (flags & 0x02) { /* Part number present */
+ if ((pCurCompressedData + 2) > pEndCompressedData) return -1;
+ pCurCompressedData += 2;
+ }
+
+ if (flags & 0x04) { /* Extra field present, starts with two-byte length */
+ if ((pCurCompressedData + 2) > pEndCompressedData) return -1;
+ unsigned short nExtraFieldLen = ((unsigned short)pCurCompressedData[0]) | (((unsigned short)pCurCompressedData[1]) << 8);
+ pCurCompressedData += 2;
+
+ if ((pCurCompressedData + nExtraFieldLen) > pEndCompressedData) return -1;
+ pCurCompressedData += nExtraFieldLen;
+ }
+
+ if (flags & 0x08) { /* Original filename present, zero terminated */
+ do {
+ if (pCurCompressedData >= pEndCompressedData) return -1;
+ pCurCompressedData++;
+ } while (pCurCompressedData[-1]);
+ }
+
+ if (flags & 0x10) { /* File comment present, zero terminated */
+ do {
+ if (pCurCompressedData >= pEndCompressedData) return -1;
+ pCurCompressedData++;
+ } while (pCurCompressedData[-1]);
+ }
+
+ if (flags & 0x20) { /* Encryption header present */
+ return -1;
+ }
+
+ nCheckSumType = EM_INFLATE_CHECKSUM_GZIP;
+ }
+ else if ((pCurCompressedData[0] & 0x0f) == 0x08) {
+ /* zlib wrapper? */
+ unsigned char CMF = pCurCompressedData[0];
+ unsigned char FLG = pCurCompressedData[1];
+ unsigned short nCheck = FLG | (((unsigned short)CMF) << 8);
+
+ if ((CMF >> 4) <= 7 && (nCheck % 31) == 0) {
+ /* Looks like a valid zlib wrapper */
+ pCurCompressedData += 2;
+ if (FLG & 0x20) { /* Preset dictionary present */
+ if ((pCurCompressedData + 4) > pEndCompressedData) return -1;
+ pCurCompressedData += 4;
+ }
+ }
+
+ nCheckSumType = EM_INFLATE_CHECKSUM_ZLIB;
+ }
+
+#ifdef EM_INFLATE_VERIFY_CHECKSUM
+ /* Initialize checksum */
+ if (nCheckSumType == EM_INFLATE_CHECKSUM_ZLIB)
+ nCheckSum = em_inflate_adler32_z(0, NULL, 0);
+#endif /* EM_INFLATE_VERIFY_CHECKSUM */
+
+ /* The rest of the data is bit-packed. Initialize bit reader */
+ em_lsb_bitreader_init(&bitReader, pCurCompressedData, pEndCompressedData);
+
+ /* Process all the blocks */
+ nCurOutOffset = 0;
+
+ do {
+ unsigned int nBlockType;
+ size_t nBlockResult;
+
+ nIsFinalBlock = em_lsb_bitreader_get_bits(&bitReader, 1);
+ nBlockType = em_lsb_bitreader_get_bits(&bitReader, 2);
+
+ switch (nBlockType) {
+ case 0: /* Stored */
+ nBlockResult = em_inflate_copy_stored(&bitReader, pOutData, nCurOutOffset, nMaxOutDataSize - nCurOutOffset);
+ break;
+
+ case 1: /* Static huffman */
+ nBlockResult = em_inflate_decompress_block(&bitReader, 0 /* static */, pOutData, nCurOutOffset, nMaxOutDataSize - nCurOutOffset);
+ break;
+
+ case 2: /* Dynamic huffman */
+ nBlockResult = em_inflate_decompress_block(&bitReader, 1 /* dynamic */, pOutData, nCurOutOffset, nMaxOutDataSize - nCurOutOffset);
+ break;
+
+ case 3: /* Invalid */
+ return -1;
+ }
+
+ if (nBlockResult == -1) return -1;
+
+#ifdef EM_INFLATE_VERIFY_CHECKSUM
+ /* Update checksum with the decompressed block's contents */
+ if (nCheckSumType == EM_INFLATE_CHECKSUM_GZIP)
+ nCheckSum = em_inflate_crc32_4bytes(pOutData + nCurOutOffset, nBlockResult, nCheckSum);
+ else if (nCheckSumType == EM_INFLATE_CHECKSUM_ZLIB)
+ nCheckSum = em_inflate_adler32_z(nCheckSum, pOutData + nCurOutOffset, nBlockResult);
+#endif /* EM_INFLATE_VERIFY_CHECKSUM */
+
+ nCurOutOffset += nBlockResult;
+ } while (!nIsFinalBlock);
+
+ /* Align on a byte again */
+ em_lsb_bitreader_byte_align(&bitReader);
+ pCurCompressedData = bitReader.pInBlock;
+
+#ifdef EM_INFLATE_VERIFY_CHECKSUM
+ /* Read stored checksum and verify it */
+
+ unsigned int nStoredCheckSum;
+ switch (nCheckSumType) {
+ case EM_INFLATE_CHECKSUM_GZIP: /* gzip - little endian crc32 */
+ if ((pCurCompressedData + 4) > pEndCompressedData) return -1;
+ nStoredCheckSum = ((unsigned int)pCurCompressedData[0]);
+ nStoredCheckSum |= ((unsigned int)pCurCompressedData[1]) << 8;
+ nStoredCheckSum |= ((unsigned int)pCurCompressedData[2]) << 16;
+ nStoredCheckSum |= ((unsigned int)pCurCompressedData[3]) << 24;
+ if (nStoredCheckSum != nCheckSum) return -1;
+ pCurCompressedData += 4;
+ break;
+
+ case EM_INFLATE_CHECKSUM_ZLIB: /* zlib - big endian adler32 */
+ if ((pCurCompressedData + 4) > pEndCompressedData) return -1;
+ nStoredCheckSum = ((unsigned int)pCurCompressedData[0]) << 24;
+ nStoredCheckSum |= ((unsigned int)pCurCompressedData[1]) << 16;
+ nStoredCheckSum |= ((unsigned int)pCurCompressedData[2]) << 8;
+ nStoredCheckSum |= ((unsigned int)pCurCompressedData[3]);
+ if (nStoredCheckSum != nCheckSum) return -1;
+ pCurCompressedData += 4;
+ break;
+
+ default: /* None */
+ break;
+ }
+#endif /* EM_INFLATE_VERIFY_CHECKSUM */
+
+ /* Success, return decompressed size */
+ return nCurOutOffset;
+}
diff --git a/3rdparty/ymfm/examples/vgmrender/em_inflate.h b/3rdparty/ymfm/examples/vgmrender/em_inflate.h
new file mode 100644
index 00000000000..6cc1a9a78bb
--- /dev/null
+++ b/3rdparty/ymfm/examples/vgmrender/em_inflate.h
@@ -0,0 +1,49 @@
+/*
+ * em_inflate.h - fast in-memory inflate (gzip/zlib decompressor) definitions
+ *
+ * Copyright (C) 2019 Emmanuel Marty
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#ifndef _EM_INFLATE_H
+#define _EM_INFLATE_H
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Inflate gzip or zlib data
+ *
+ * @param pCompressedData pointer to start of zlib data
+ * @param nCompressedDataSize size of zlib data, in bytes
+ * @param pOutData pointer to start of decompression buffer
+ * @param nMaxOutDataSize maximum size of decompression buffer, in bytes
+ *
+ * @return number of bytes decompressed, or -1 in case of an error
+ */
+size_t em_inflate(const void *pCompressedData, size_t nCompressedDataSize, unsigned char *pOutData, size_t nMaxOutDataSize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EM_INFLATE_H */
diff --git a/3rdparty/ymfm/examples/vgmrender/vgmrender.cpp b/3rdparty/ymfm/examples/vgmrender/vgmrender.cpp
new file mode 100644
index 00000000000..fd99d432ae4
--- /dev/null
+++ b/3rdparty/ymfm/examples/vgmrender/vgmrender.cpp
@@ -0,0 +1,1412 @@
+//
+// Simple vgm renderer.
+//
+// Leverages em_inflate tiny inflater from https://github.com/emmanuel-marty/em_inflate
+//
+// Compile with:
+//
+// g++ --std=c++14 -I../../src vgmrender.cpp em_inflate.cpp ../../src/ymfm_misc.cpp ../../src/ymfm_opl.cpp ../../src/ymfm_opm.cpp ../../src/ymfm_opn.cpp ../../src/ymfm_adpcm.cpp ../../src/ymfm_pcm.cpp ../../src/ymfm_ssg.cpp -o vgmrender.exe
+//
+// or:
+//
+// clang --std=c++14 -I../../src vgmrender.cpp em_inflate.cpp ../../src/ymfm_misc.cpp ../../src/ymfm_opl.cpp ../../src/ymfm_opm.cpp ../../src/ymfm_opn.cpp ../../src/ymfm_adpcm.cpp ../../src/ymfm_pcm.cpp ../../src/ymfm_ssg.cpp -o vgmrender.exe
+//
+// or:
+//
+// cl -I..\..\src vgmrender.cpp em_inflate.cpp ..\..\src\ymfm_misc.cpp ..\..\src\ymfm_opl.cpp ..\..\src\ymfm_opm.cpp ..\..\src\ymfm_opn.cpp ..\..\src\ymfm_adpcm.cpp ..\..\src\ymfm_pcm.cpp ..\..\src\ymfm_ssg.cpp /Od /Zi /std:c++14 /EHsc
+//
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <cmath>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <list>
+#include <string>
+
+#include "em_inflate.h"
+#include "ymfm_misc.h"
+#include "ymfm_opl.h"
+#include "ymfm_opm.h"
+#include "ymfm_opn.h"
+
+#define LOG_WRITES (0)
+
+// enable this to run the nuked OPN2 core in parallel; output is not captured,
+// but logging can be added to observe behaviors
+#define RUN_NUKED_OPN2 (0)
+#if (RUN_NUKED_OPN2)
+namespace nuked {
+#include "test/ym3438.h"
+}
+#endif
+
+// enable this to capture each chip at its native rate as well
+#define CAPTURE_NATIVE (0 || RUN_NUKED_OPN2)
+
+
+
+//*********************************************************
+// GLOBAL TYPES
+//*********************************************************
+
+// we use an int64_t as emulated time, as a 32.32 fixed point value
+using emulated_time = int64_t;
+
+// enumeration of the different types of chips we support
+enum chip_type
+{
+ CHIP_YM2149,
+ CHIP_YM2151,
+ CHIP_YM2203,
+ CHIP_YM2413,
+ CHIP_YM2608,
+ CHIP_YM2610,
+ CHIP_YM2612,
+ CHIP_YM3526,
+ CHIP_Y8950,
+ CHIP_YM3812,
+ CHIP_YMF262,
+ CHIP_YMF278B,
+ CHIP_TYPES
+};
+
+
+
+//*********************************************************
+// CLASSES
+//*********************************************************
+
+// ======================> vgm_chip_base
+
+// abstract base class for a Yamaha chip; we keep a list of these for processing
+// as new commands come in
+class vgm_chip_base
+{
+public:
+ // construction
+ vgm_chip_base(uint32_t clock, chip_type type, char const *name) :
+ m_type(type),
+ m_name(name)
+ {
+ }
+
+ // simple getters
+ chip_type type() const { return m_type; }
+ virtual uint32_t sample_rate() const = 0;
+
+ // required methods for derived classes to implement
+ virtual void write(uint32_t reg, uint8_t data) = 0;
+ virtual void generate(emulated_time output_start, emulated_time output_step, int32_t *buffer) = 0;
+
+ // write data to the ADPCM-A buffer
+ void write_data(ymfm::access_class type, uint32_t base, uint32_t length, uint8_t const *src)
+ {
+ uint32_t end = base + length;
+ if (end > m_data[type].size())
+ m_data[type].resize(end);
+ memcpy(&m_data[type][base], src, length);
+ }
+
+ // seek within the PCM stream
+ void seek_pcm(uint32_t pos) { m_pcm_offset = pos; }
+ uint8_t read_pcm() { auto &pcm = m_data[ymfm::ACCESS_PCM]; return (m_pcm_offset < pcm.size()) ? pcm[m_pcm_offset++] : 0; }
+
+protected:
+ // internal state
+ chip_type m_type;
+ std::string m_name;
+ std::vector<uint8_t> m_data[ymfm::ACCESS_CLASSES];
+ uint32_t m_pcm_offset;
+#if (CAPTURE_NATIVE)
+public:
+ std::vector<int32_t> m_native_data;
+#endif
+#if (RUN_NUKED_OPN2)
+public:
+ nuked::ym3438_t *m_external = nullptr;
+ std::vector<int32_t> m_nuked_data;
+#endif
+};
+
+
+// ======================> vgm_chip
+
+// actual chip-specific implementation class; includes implementatino of the
+// ymfm_interface as needed for vgmplay purposes
+template<typename ChipType>
+class vgm_chip : public vgm_chip_base, public ymfm::ymfm_interface
+{
+public:
+ // construction
+ vgm_chip(uint32_t clock, chip_type type, char const *name) :
+ vgm_chip_base(clock, type, name),
+ m_chip(*this),
+ m_clock(clock),
+ m_clocks(0),
+ m_step(0x100000000ull / m_chip.sample_rate(clock)),
+ m_pos(0)
+ {
+ m_chip.reset();
+#if (RUN_NUKED_OPN2)
+ if (type == CHIP_YM2612)
+ {
+ m_external = new nuked::ym3438_t;
+ nuked::OPN2_SetChipType(nuked::ym3438_mode_ym2612);
+ nuked::OPN2_Reset(m_external);
+ }
+#endif
+ }
+
+ virtual uint32_t sample_rate() const override
+ {
+ return m_chip.sample_rate(m_clock);
+ }
+
+ // handle a register write: just queue for now
+ virtual void write(uint32_t reg, uint8_t data) override
+ {
+ m_queue.push_back(std::make_pair(reg, data));
+ }
+
+ // generate one output sample of output
+ virtual void generate(emulated_time output_start, emulated_time output_step, int32_t *buffer) override
+ {
+ uint32_t addr1 = 0xffff, addr2 = 0xffff;
+ uint8_t data1 = 0, data2 = 0;
+
+ // see if there is data to be written; if so, extract it and dequeue
+ if (!m_queue.empty())
+ {
+ auto front = m_queue.front();
+ addr1 = 0 + 2 * ((front.first >> 8) & 3);
+ data1 = front.first & 0xff;
+ addr2 = addr1 + ((m_type == CHIP_YM2149) ? 2 : 1);
+ data2 = front.second;
+ m_queue.erase(m_queue.begin());
+ }
+
+ // write to the chip
+ if (addr1 != 0xffff)
+ {
+ if (LOG_WRITES)
+ printf("%10.5f: %s %03X=%02X\n", double(m_clocks) / double(m_chip.sample_rate(m_clock)), m_name.c_str(), data1, data2);
+ m_chip.write(addr1, data1);
+ m_chip.write(addr2, data2);
+ }
+
+ // generate at the appropriate sample rate
+ for ( ; m_pos <= output_start; m_pos += m_step)
+ {
+ m_chip.generate(&m_output);
+
+#if (CAPTURE_NATIVE)
+ // if capturing native, append each generated sample
+ m_native_data.push_back(m_output.data[0]);
+ m_native_data.push_back(m_output.data[ChipType::OUTPUTS > 1 ? 1 : 0]);
+#endif
+
+#if (RUN_NUKED_OPN2)
+ // if running nuked, capture its output as well
+ if (m_external != nullptr)
+ {
+ int32_t sum[2] = { 0 };
+ if (addr1 != 0xffff)
+ nuked::OPN2_Write(m_external, addr1, data1);
+ nuked::Bit16s buffer[2];
+ for (int clocks = 0; clocks < 12; clocks++)
+ {
+ nuked::OPN2_Clock(m_external, buffer);
+ sum[0] += buffer[0];
+ sum[1] += buffer[1];
+ }
+ if (addr2 != 0xffff)
+ nuked::OPN2_Write(m_external, addr2, data2);
+ for (int clocks = 0; clocks < 12; clocks++)
+ {
+ nuked::OPN2_Clock(m_external, buffer);
+ sum[0] += buffer[0];
+ sum[1] += buffer[1];
+ }
+ addr1 = addr2 = 0xffff;
+ m_nuked_data.push_back(sum[0] / 24);
+ m_nuked_data.push_back(sum[1] / 24);
+ }
+#endif
+ }
+
+ // add the final result to the buffer
+ if (m_type == CHIP_YM2203)
+ {
+ int32_t out0 = m_output.data[0];
+ int32_t out1 = m_output.data[1 % ChipType::OUTPUTS];
+ int32_t out2 = m_output.data[2 % ChipType::OUTPUTS];
+ int32_t out3 = m_output.data[3 % ChipType::OUTPUTS];
+ *buffer++ += out0 + out1 + out2 + out3;
+ *buffer++ += out0 + out1 + out2 + out3;
+ }
+ else if (m_type == CHIP_YM2608 || m_type == CHIP_YM2610)
+ {
+ int32_t out0 = m_output.data[0];
+ int32_t out1 = m_output.data[1 % ChipType::OUTPUTS];
+ int32_t out2 = m_output.data[2 % ChipType::OUTPUTS];
+ *buffer++ += out0 + out2;
+ *buffer++ += out1 + out2;
+ }
+ else if (m_type == CHIP_YMF278B)
+ {
+ *buffer++ += m_output.data[4];
+ *buffer++ += m_output.data[5];
+ }
+ else if (ChipType::OUTPUTS == 1)
+ {
+ *buffer++ += m_output.data[0];
+ *buffer++ += m_output.data[0];
+ }
+ else
+ {
+ *buffer++ += m_output.data[0];
+ *buffer++ += m_output.data[1 % ChipType::OUTPUTS];
+ }
+ m_clocks++;
+ }
+
+protected:
+ // handle a read from the buffer
+ virtual uint8_t ymfm_external_read(ymfm::access_class type, uint32_t offset) override
+ {
+ auto &data = m_data[type];
+ return (offset < data.size()) ? data[offset] : 0;
+ }
+
+ // internal state
+ ChipType m_chip;
+ uint32_t m_clock;
+ uint64_t m_clocks;
+ typename ChipType::output_data m_output;
+ emulated_time m_step;
+ emulated_time m_pos;
+ std::vector<std::pair<uint32_t, uint8_t>> m_queue;
+};
+
+
+
+//*********************************************************
+// GLOBAL HELPERS
+//*********************************************************
+
+// global list of active chips
+std::list<vgm_chip_base *> active_chips;
+
+
+//-------------------------------------------------
+// parse_uint32 - parse a little-endian uint32_t
+//-------------------------------------------------
+
+uint32_t parse_uint32(std::vector<uint8_t> &buffer, uint32_t &offset)
+{
+ uint32_t result = buffer[offset++];
+ result |= buffer[offset++] << 8;
+ result |= buffer[offset++] << 16;
+ result |= buffer[offset++] << 24;
+ return result;
+}
+
+
+//-------------------------------------------------
+// add_chips - add 1 or 2 instances of the given
+// supported chip type
+//-------------------------------------------------
+
+template<typename ChipType>
+void add_chips(uint32_t clock, chip_type type, char const *chipname)
+{
+ uint32_t clockval = clock & 0x3fffffff;
+ int numchips = (clock & 0x40000000) ? 2 : 1;
+ printf("Adding %s%s @ %dHz\n", (numchips == 2) ? "2 x " : "", chipname, clockval);
+ for (int index = 0; index < numchips; index++)
+ {
+ char name[100];
+ sprintf(name, "%s #%d", chipname, index);
+ active_chips.push_back(new vgm_chip<ChipType>(clockval, type, chipname));
+ }
+
+ if (type == CHIP_YM2608)
+ {
+ FILE *rom = fopen("ym2608_adpcm_rom.bin", "rb");
+ if (rom == nullptr)
+ fprintf(stderr, "Warning: YM2608 enabled but ym2608_adpcm_rom.bin not found\n");
+ else
+ {
+ fseek(rom, 0, SEEK_END);
+ uint32_t size = ftell(rom);
+ fseek(rom, 0, SEEK_SET);
+ std::vector<uint8_t> temp(size);
+ fread(&temp[0], 1, size, rom);
+ fclose(rom);
+ for (auto chip : active_chips)
+ if (chip->type() == type)
+ chip->write_data(ymfm::ACCESS_ADPCM_A, 0, size, &temp[0]);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// parse_header - parse the vgm header, adding
+// chips for anything we encounter that we can
+// support
+//-------------------------------------------------
+
+uint32_t parse_header(std::vector<uint8_t> &buffer)
+{
+ // +00: already checked the ID
+ uint32_t offset = 4;
+
+ // +04: parse the size
+ uint32_t size = parse_uint32(buffer, offset);
+ if (offset - 4 + size > buffer.size())
+ {
+ fprintf(stderr, "Total size for file is too small; file may be truncated\n");
+ size = buffer.size() - 4;
+ }
+ buffer.resize(size + 4);
+
+ // +08: parse the version
+ uint32_t version = parse_uint32(buffer, offset);
+ if (version > 0x171)
+ fprintf(stderr, "Warning: version > 1.71 detected, some things may not work\n");
+
+ // +0C: SN76489 clock
+ uint32_t clock = parse_uint32(buffer, offset);
+ if (clock != 0)
+ fprintf(stderr, "Warning: clock for SN76489 specified (%d), but not supported\n", clock);
+
+ // +10: YM2413 clock
+ clock = parse_uint32(buffer, offset);
+ if (clock != 0)
+ add_chips<ymfm::ym2413>(clock, CHIP_YM2413, "YM2413");
+
+ // +14: GD3 offset
+ uint32_t dummy = parse_uint32(buffer, offset);
+
+ // +18: Total # samples
+ dummy = parse_uint32(buffer, offset);
+
+ // +1C: Loop offset
+ dummy = parse_uint32(buffer, offset);
+
+ // +20: Loop # samples
+ dummy = parse_uint32(buffer, offset);
+
+ // +24: Rate
+ dummy = parse_uint32(buffer, offset);
+
+ // +28: SN76489 feedback / SN76489 shift register width / SN76489 Flags
+ dummy = parse_uint32(buffer, offset);
+
+ // +2C: YM2612 clock
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x110 && clock != 0)
+ add_chips<ymfm::ym2612>(clock, CHIP_YM2612, "YM2612");
+
+ // +30: YM2151 clock
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x110 && clock != 0)
+ add_chips<ymfm::ym2151>(clock, CHIP_YM2151, "YM2151");
+
+ // +34: VGM data offset
+ uint32_t data_start = parse_uint32(buffer, offset);
+ data_start += offset - 4;
+ if (version < 0x150)
+ data_start = 0x40;
+
+ // +38: Sega PCM clock
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ fprintf(stderr, "Warning: clock for Sega PCM specified, but not supported\n");
+
+ // +3C: Sega PCM interface register
+ dummy = parse_uint32(buffer, offset);
+
+ // +40: RF5C68 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ fprintf(stderr, "Warning: clock for RF5C68 specified, but not supported\n");
+
+ // +44: YM2203 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ add_chips<ymfm::ym2203>(clock, CHIP_YM2203, "YM2203");
+
+ // +48: YM2608 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ add_chips<ymfm::ym2608>(clock, CHIP_YM2608, "YM2608");
+
+ // +4C: YM2610/2610B clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ {
+ if (clock & 0x80000000)
+ add_chips<ymfm::ym2610b>(clock, CHIP_YM2610, "YM2610B");
+ else
+ add_chips<ymfm::ym2610>(clock, CHIP_YM2610, "YM2610");
+ }
+
+ // +50: YM3812 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ add_chips<ymfm::ym3812>(clock, CHIP_YM3812, "YM3812");
+
+ // +54: YM3526 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ add_chips<ymfm::ym3526>(clock, CHIP_YM3526, "YM3526");
+
+ // +58: Y8950 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ add_chips<ymfm::y8950>(clock, CHIP_Y8950, "Y8950");
+
+ // +5C: YMF262 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ add_chips<ymfm::ymf262>(clock, CHIP_YMF262, "YMF262");
+
+ // +60: YMF278B clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ add_chips<ymfm::ymf278b>(clock, CHIP_YMF278B, "YMF278B");
+
+ // +64: YMF271 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ fprintf(stderr, "Warning: clock for YMF271 specified, but not supported\n");
+
+ // +68: YMF280B clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ fprintf(stderr, "Warning: clock for YMF280B specified, but not supported\n");
+
+ // +6C: RF5C164 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ fprintf(stderr, "Warning: clock for RF5C164 specified, but not supported\n");
+
+ // +70: PWM clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ fprintf(stderr, "Warning: clock for PWM specified, but not supported\n");
+
+ // +74: AY8910 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x151 && clock != 0)
+ {
+ fprintf(stderr, "Warning: clock for AY8910 specified, substituting YM2149\n");
+ add_chips<ymfm::ym2149>(clock, CHIP_YM2149, "YM2149");
+ }
+
+ // +78: AY8910 flags
+ if (offset + 4 > data_start)
+ return data_start;
+ dummy = parse_uint32(buffer, offset);
+
+ // +7C: volume / loop info
+ if (offset + 4 > data_start)
+ return data_start;
+ dummy = parse_uint32(buffer, offset);
+ if ((dummy & 0xff) != 0)
+ printf("Volume modifier: %02X (=%d)\n", dummy & 0xff, int(pow(2, double(dummy & 0xff) / 0x20)));
+
+ // +80: GameBoy DMG clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for GameBoy DMG specified, but not supported\n");
+
+ // +84: NES APU clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for NES APU specified, but not supported\n");
+
+ // +88: MultiPCM clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for MultiPCM specified, but not supported\n");
+
+ // +8C: uPD7759 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for uPD7759 specified, but not supported\n");
+
+ // +90: OKIM6258 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for OKIM6258 specified, but not supported\n");
+
+ // +94: OKIM6258 Flags / K054539 Flags / C140 Chip Type / reserved
+ if (offset + 4 > data_start)
+ return data_start;
+ dummy = parse_uint32(buffer, offset);
+
+ // +98: OKIM6295 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for OKIM6295 specified, but not supported\n");
+
+ // +9C: K051649 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for K051649 specified, but not supported\n");
+
+ // +A0: K054539 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for K054539 specified, but not supported\n");
+
+ // +A4: HuC6280 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for HuC6280 specified, but not supported\n");
+
+ // +A8: C140 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for C140 specified, but not supported\n");
+
+ // +AC: K053260 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for K053260 specified, but not supported\n");
+
+ // +B0: Pokey clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for Pokey specified, but not supported\n");
+
+ // +B4: QSound clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x161 && clock != 0)
+ fprintf(stderr, "Warning: clock for QSound specified, but not supported\n");
+
+ // +B8: SCSP clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x171 && clock != 0)
+ fprintf(stderr, "Warning: clock for SCSP specified, but not supported\n");
+
+ // +BC: extra header offset
+ if (offset + 4 > data_start)
+ return data_start;
+ uint32_t extra_header = parse_uint32(buffer, offset);
+
+ // +C0: WonderSwan clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x171 && clock != 0)
+ fprintf(stderr, "Warning: clock for WonderSwan specified, but not supported\n");
+
+ // +C4: VSU clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x171 && clock != 0)
+ fprintf(stderr, "Warning: clock for VSU specified, but not supported\n");
+
+ // +C8: SAA1099 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x171 && clock != 0)
+ fprintf(stderr, "Warning: clock for SAA1099 specified, but not supported\n");
+
+ // +CC: ES5503 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x171 && clock != 0)
+ fprintf(stderr, "Warning: clock for ES5503 specified, but not supported\n");
+
+ // +D0: ES5505/ES5506 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x171 && clock != 0)
+ fprintf(stderr, "Warning: clock for ES5505/ES5506 specified, but not supported\n");
+
+ // +D4: ES5503 output channels / ES5505/ES5506 amount of output channels / C352 clock divider
+ if (offset + 4 > data_start)
+ return data_start;
+ dummy = parse_uint32(buffer, offset);
+
+ // +D8: X1-010 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x171 && clock != 0)
+ fprintf(stderr, "Warning: clock for X1-010 specified, but not supported\n");
+
+ // +DC: C352 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x171 && clock != 0)
+ fprintf(stderr, "Warning: clock for C352 specified, but not supported\n");
+
+ // +E0: GA20 clock
+ if (offset + 4 > data_start)
+ return data_start;
+ clock = parse_uint32(buffer, offset);
+ if (version >= 0x171 && clock != 0)
+ fprintf(stderr, "Warning: clock for GA20 specified, but not supported\n");
+
+ return data_start;
+}
+
+
+//-------------------------------------------------
+// find_chip - find the given chip and index
+//-------------------------------------------------
+
+vgm_chip_base *find_chip(chip_type type, uint8_t index)
+{
+ for (auto chip : active_chips)
+ if (chip->type() == type && index-- == 0)
+ return chip;
+ return nullptr;
+}
+
+
+//-------------------------------------------------
+// write_chip - handle a write to the given chip
+// and index
+//-------------------------------------------------
+
+void write_chip(chip_type type, uint8_t index, uint32_t reg, uint8_t data)
+{
+ vgm_chip_base *chip = find_chip(type, index);
+ if (chip != nullptr)
+ chip->write(reg, data);
+}
+
+
+//-------------------------------------------------
+// add_rom_data - add data to the given chip
+// type in the given access class
+//-------------------------------------------------
+
+void add_rom_data(chip_type type, ymfm::access_class access, std::vector<uint8_t> &buffer, uint32_t &localoffset, uint32_t size)
+{
+ uint32_t length = parse_uint32(buffer, localoffset);
+ uint32_t start = parse_uint32(buffer, localoffset);
+ for (int index = 0; index < 2; index++)
+ {
+ vgm_chip_base *chip = find_chip(type, index);
+ if (chip != nullptr)
+ chip->write_data(access, start, size, &buffer[localoffset]);
+ }
+}
+
+
+//-------------------------------------------------
+// generate_all - generate everything described
+// in the vgmplay file
+//-------------------------------------------------
+
+void generate_all(std::vector<uint8_t> &buffer, uint32_t data_start, uint32_t output_rate, std::vector<int32_t> &wav_buffer)
+{
+ // set the offset to the data start and go
+ uint32_t offset = data_start;
+ bool done = false;
+ emulated_time output_step = 0x100000000ull / output_rate;
+ emulated_time output_pos = 0;
+ while (!done && offset < buffer.size())
+ {
+ int delay = 0;
+ uint8_t cmd = buffer[offset++];
+ switch (cmd)
+ {
+ // YM2413, write value dd to register aa
+ case 0x51:
+ case 0xa1:
+ write_chip(CHIP_YM2413, cmd >> 7, buffer[offset], buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // YM2612 port 0, write value dd to register aa
+ case 0x52:
+ case 0xa2:
+ write_chip(CHIP_YM2612, cmd >> 7, buffer[offset], buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // YM2612 port 1, write value dd to register aa
+ case 0x53:
+ case 0xa3:
+ write_chip(CHIP_YM2612, cmd >> 7, buffer[offset] | 0x100, buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // YM2151, write value dd to register aa
+ case 0x54:
+ case 0xa4:
+ write_chip(CHIP_YM2151, cmd >> 7, buffer[offset], buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // YM2203, write value dd to register aa
+ case 0x55:
+ case 0xa5:
+ write_chip(CHIP_YM2203, cmd >> 7, buffer[offset], buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // YM2608 port 0, write value dd to register aa
+ case 0x56:
+ case 0xa6:
+ write_chip(CHIP_YM2608, cmd >> 7, buffer[offset], buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // YM2608 port 1, write value dd to register aa
+ case 0x57:
+ case 0xa7:
+ write_chip(CHIP_YM2608, cmd >> 7, buffer[offset] | 0x100, buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // YM2610 port 0, write value dd to register aa
+ case 0x58:
+ case 0xa8:
+ write_chip(CHIP_YM2610, cmd >> 7, buffer[offset], buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // YM2610 port 1, write value dd to register aa
+ case 0x59:
+ case 0xa9:
+ write_chip(CHIP_YM2610, cmd >> 7, buffer[offset] | 0x100, buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // YM3812, write value dd to register aa
+ case 0x5a:
+ case 0xaa:
+ write_chip(CHIP_YM3812, cmd >> 7, buffer[offset], buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // YM3526, write value dd to register aa
+ case 0x5b:
+ case 0xab:
+ write_chip(CHIP_YM3526, cmd >> 7, buffer[offset], buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // Y8950, write value dd to register aa
+ case 0x5c:
+ case 0xac:
+ write_chip(CHIP_Y8950, cmd >> 7, buffer[offset], buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // YMF262 port 0, write value dd to register aa
+ case 0x5e:
+ case 0xae:
+ write_chip(CHIP_YMF262, cmd >> 7, buffer[offset], buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // YMF262 port 1, write value dd to register aa
+ case 0x5f:
+ case 0xaf:
+ write_chip(CHIP_YMF262, cmd >> 7, buffer[offset] | 0x100, buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // Wait n samples, n can range from 0 to 65535 (approx 1.49 seconds)
+ case 0x61:
+ delay = buffer[offset] | (buffer[offset + 1] << 8);
+ offset += 2;
+ break;
+
+ // wait 735 samples (60th of a second)
+ case 0x62:
+ delay = 735;
+ break;
+
+ // wait 882 samples (50th of a second)
+ case 0x63:
+ delay = 882;
+ break;
+
+ // end of sound data
+ case 0x66:
+ done = true;
+ break;
+
+ // data block
+ case 0x67:
+ {
+ uint8_t dummy = buffer[offset++];
+ if (dummy != 0x66)
+ break;
+ uint8_t type = buffer[offset++];
+ uint32_t size = parse_uint32(buffer, offset);
+ uint32_t start, length;
+ uint32_t localoffset = offset;
+
+ switch (type)
+ {
+ case 0x01: // RF5C68 PCM data for use with associated commands
+ case 0x02: // RF5C164 PCM data for use with associated commands
+ case 0x03: // PWM PCM data for use with associated commands
+ case 0x04: // OKIM6258 ADPCM data for use with associated commands
+ case 0x05: // HuC6280 PCM data for use with associated commands
+ case 0x06: // SCSP PCM data for use with associated commands
+ case 0x07: // NES APU DPCM data for use with associated commands
+ break;
+
+ case 0x00: // YM2612 PCM data for use with associated commands
+ {
+ vgm_chip_base *chip = find_chip(CHIP_YM2612, 0);
+ if (chip != nullptr)
+ chip->write_data(ymfm::ACCESS_PCM, 0, size - 8, &buffer[localoffset]);
+ break;
+ }
+
+ case 0x82: // YM2610 ADPCM ROM data
+ add_rom_data(CHIP_YM2610, ymfm::ACCESS_ADPCM_A, buffer, localoffset, size - 8);
+ break;
+
+ case 0x81: // YM2608 DELTA-T ROM data
+ add_rom_data(CHIP_YM2608, ymfm::ACCESS_ADPCM_B, buffer, localoffset, size - 8);
+ break;
+
+ case 0x83: // YM2610 DELTA-T ROM data
+ add_rom_data(CHIP_YM2610, ymfm::ACCESS_ADPCM_B, buffer, localoffset, size - 8);
+ break;
+
+ case 0x84: // YMF278B ROM data
+ case 0x87: // YMF278B RAM data
+ add_rom_data(CHIP_YMF278B, ymfm::ACCESS_PCM, buffer, localoffset, size - 8);
+ break;
+
+ case 0x88: // Y8950 DELTA-T ROM data
+ add_rom_data(CHIP_Y8950, ymfm::ACCESS_ADPCM_B, buffer, localoffset, size - 8);
+ break;
+
+ case 0x80: // Sega PCM ROM data
+ case 0x85: // YMF271 ROM data
+ case 0x86: // YMZ280B ROM data
+ case 0x89: // MultiPCM ROM data
+ case 0x8A: // uPD7759 ROM data
+ case 0x8B: // OKIM6295 ROM data
+ case 0x8C: // K054539 ROM data
+ case 0x8D: // C140 ROM data
+ case 0x8E: // K053260 ROM data
+ case 0x8F: // Q-Sound ROM data
+ case 0x90: // ES5505/ES5506 ROM data
+ case 0x91: // X1-010 ROM data
+ case 0x92: // C352 ROM data
+ case 0x93: // GA20 ROM data
+ break;
+
+ case 0xC0: // RF5C68 RAM write
+ case 0xC1: // RF5C164 RAM write
+ case 0xC2: // NES APU RAM write
+ case 0xE0: // SCSP RAM write
+ case 0xE1: // ES5503 RAM write
+ break;
+
+ default:
+ if (type >= 0x40 && type < 0x7f)
+ printf("Compressed data block not supported\n");
+ else
+ printf("Unknown data block type 0x%02X\n", type);
+ break;
+ }
+ offset += size;
+ break;
+ }
+
+ // PCM RAM write
+ case 0x68:
+ printf("68: PCM RAM write\n");
+ break;
+
+ // AY8910, write value dd to register aa
+ case 0xa0:
+ write_chip(CHIP_YM2149, buffer[offset] >> 7, buffer[offset] & 0x7f, buffer[offset + 1]);
+ offset += 2;
+ break;
+
+ // pp aa dd: YMF278B, port pp, write value dd to register aa
+ case 0xd0:
+ write_chip(CHIP_YMF278B, buffer[offset] >> 7, ((buffer[offset] & 0x7f) << 8) | buffer[offset + 1], buffer[offset + 2]);
+ offset += 3;
+ 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:
+ delay = (cmd & 15) + 1;
+ 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:
+ {
+ vgm_chip_base *chip = find_chip(CHIP_YM2612, 0);
+ if (chip != nullptr)
+ chip->write(0x2a, chip->read_pcm());
+ delay = cmd & 15;
+ break;
+ }
+
+ // ignored, consume one byte
+ 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:
+ case 0x4f: // dd: Game Gear PSG stereo, write dd to port 0x06
+ case 0x50: // dd: PSG (SN76489/SN76496) write value dd
+ offset++;
+ break;
+
+ // ignored, consume two bytes
+ 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 0x5d: // aa dd: YMZ280B, write value dd to register aa
+ case 0xb0: // aa dd: RF5C68, write value dd to register aa
+ case 0xb1: // aa dd: RF5C164, write value dd to register aa
+ case 0xb2: // aa dd: PWM, write value ddd to register a (d is MSB, dd is LSB)
+ case 0xb3: // aa dd: GameBoy DMG, write value dd to register aa
+ case 0xb4: // aa dd: NES APU, write value dd to register aa
+ case 0xb5: // aa dd: MultiPCM, write value dd to register aa
+ case 0xb6: // aa dd: uPD7759, write value dd to register aa
+ case 0xb7: // aa dd: OKIM6258, write value dd to register aa
+ case 0xb8: // aa dd: OKIM6295, write value dd to register aa
+ case 0xb9: // aa dd: HuC6280, write value dd to register aa
+ case 0xba: // aa dd: K053260, write value dd to register aa
+ case 0xbb: // aa dd: Pokey, write value dd to register aa
+ case 0xbc: // aa dd: WonderSwan, write value dd to register aa
+ case 0xbd: // aa dd: SAA1099, write value dd to register aa
+ case 0xbe: // aa dd: ES5506, write value dd to register aa
+ case 0xbf: // aa dd: GA20, write value dd to register aa
+ offset += 2;
+ break;
+
+ // ignored, consume three bytes
+ case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
+ case 0xd7: case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
+ case 0xc0: // bbaa dd: Sega PCM, write value dd to memory offset aabb
+ case 0xc1: // bbaa dd: RF5C68, write value dd to memory offset aabb
+ case 0xc2: // bbaa dd: RF5C164, write value dd to memory offset aabb
+ case 0xc3: // cc bbaa: MultiPCM, write set bank offset aabb to channel cc
+ case 0xc4: // mmll rr: QSound, write value mmll to register rr (mm - data MSB, ll - data LSB)
+ case 0xc5: // mmll dd: SCSP, write value dd to memory offset mmll (mm - offset MSB, ll - offset LSB)
+ case 0xc6: // mmll dd: WonderSwan, write value dd to memory offset mmll (mm - offset MSB, ll - offset LSB)
+ case 0xc7: // mmll dd: VSU, write value dd to memory offset mmll (mm - offset MSB, ll - offset LSB)
+ case 0xc8: // mmll dd: X1-010, write value dd to memory offset mmll (mm - offset MSB, ll - offset LSB)
+ case 0xd1: // pp aa dd: YMF271, port pp, write value dd to register aa
+ case 0xd2: // pp aa dd: SCC1, port pp, write value dd to register aa
+ case 0xd3: // pp aa dd: K054539, write value dd to register ppaa
+ case 0xd4: // pp aa dd: C140, write value dd to register ppaa
+ case 0xd5: // pp aa dd: ES5503, write value dd to register ppaa
+ case 0xd6: // pp aa dd: ES5506, write value aadd to register pp
+ offset += 3;
+ break;
+
+ // ignored, consume four bytes
+ case 0xe0: // dddddddd: Seek to offset dddddddd (Intel byte order) in PCM data bank of data block type 0 (YM2612).
+ {
+ vgm_chip_base *chip = find_chip(CHIP_YM2612, 0);
+ uint32_t pos = parse_uint32(buffer, offset);
+ if (chip != nullptr)
+ chip->seek_pcm(pos);
+ offset += 4;
+ break;
+ }
+ case 0xe1: // mmll aadd: C352, write value aadd to register mmll
+ 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:
+ offset += 4;
+ break;
+ }
+
+ // handle delays
+ while (delay-- != 0)
+ {
+ bool more_remaining = false;
+ int32_t outputs[2] = { 0 };
+ for (auto chip : active_chips)
+ chip->generate(output_pos, output_step, outputs);
+ output_pos += output_step;
+ wav_buffer.push_back(outputs[0]);
+ wav_buffer.push_back(outputs[1]);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// write_wav - write a WAV file from the provided
+// stereo data
+//-------------------------------------------------
+
+int write_wav(char const *filename, uint32_t output_rate, std::vector<int32_t> &wav_buffer_src)
+{
+ // determine normalization parameters
+ int32_t max_scale = 0;
+ for (int index = 0; index < wav_buffer_src.size(); index++)
+ {
+ int32_t absval = std::abs(wav_buffer_src[index]);
+ max_scale = std::max(max_scale, absval);
+ }
+
+ // now convert
+ std::vector<int16_t> wav_buffer(wav_buffer_src.size());
+ for (int index = 0; index < wav_buffer_src.size(); index++)
+ wav_buffer[index] = wav_buffer_src[index] * 26000 / max_scale;
+
+ // write the WAV file
+ FILE *out = fopen(filename, "wb");
+ if (out == nullptr)
+ {
+ fprintf(stderr, "Error creating output file '%s'\n", filename);
+ return 6;
+ }
+
+ // write the 'RIFF' header
+ if (fwrite("RIFF", 1, 4, out) != 4)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the total size
+ uint32_t total_size = 48 + wav_buffer.size() * 2 - 8;
+ uint8_t wavdata[4];
+ wavdata[0] = total_size >> 0;
+ wavdata[1] = total_size >> 8;
+ wavdata[2] = total_size >> 16;
+ wavdata[3] = total_size >> 24;
+ if (fwrite(wavdata, 1, 4, out) != 4)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the 'WAVE' type
+ if (fwrite("WAVE", 1, 4, out) != 4)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the 'fmt ' tag
+ if (fwrite("fmt ", 1, 4, out) != 4)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the format length
+ wavdata[0] = 16;
+ wavdata[1] = 0;
+ wavdata[2] = 0;
+ wavdata[3] = 0;
+ if (fwrite(wavdata, 1, 4, out) != 4)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the format (PCM)
+ wavdata[0] = 1;
+ wavdata[1] = 0;
+ if (fwrite(wavdata, 1, 2, out) != 2)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the channels
+ wavdata[0] = 2;
+ wavdata[1] = 0;
+ if (fwrite(wavdata, 1, 2, out) != 2)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the sample rate
+ wavdata[0] = output_rate >> 0;
+ wavdata[1] = output_rate >> 8;
+ wavdata[2] = output_rate >> 16;
+ wavdata[3] = output_rate >> 24;
+ if (fwrite(wavdata, 1, 4, out) != 4)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the bytes/second
+ uint32_t bps = output_rate * 2 * 2;
+ wavdata[0] = bps >> 0;
+ wavdata[1] = bps >> 8;
+ wavdata[2] = bps >> 16;
+ wavdata[3] = bps >> 24;
+ if (fwrite(wavdata, 1, 4, out) != 4)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the block align
+ wavdata[0] = 4;
+ wavdata[1] = 0;
+ if (fwrite(wavdata, 1, 2, out) != 2)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the bits/sample
+ wavdata[0] = 16;
+ wavdata[1] = 0;
+ if (fwrite(wavdata, 1, 2, out) != 2)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the 'data' tag
+ if (fwrite("data", 1, 4, out) != 4)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the data length
+ uint32_t datalen = wav_buffer.size() * 2;
+ wavdata[0] = datalen >> 0;
+ wavdata[1] = datalen >> 8;
+ wavdata[2] = datalen >> 16;
+ wavdata[3] = datalen >> 24;
+ if (fwrite(wavdata, 1, 4, out) != 4)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+
+ // write the data
+ if (fwrite(&wav_buffer[0], 1, datalen, out) != datalen)
+ {
+ fprintf(stderr, "Error writing to output file\n");
+ return 7;
+ }
+ fclose(out);
+ return 0;
+}
+
+
+//-------------------------------------------------
+// main - program entry point
+//-------------------------------------------------
+
+int main(int argc, char *argv[])
+{
+ char const *filename = nullptr;
+ char const *outfilename = nullptr;
+ int output_rate = 44100;
+
+ // parse command line
+ bool argerr = false;
+ for (int arg = 1; arg < argc; arg++)
+ {
+ char const *curarg = argv[arg];
+ if (*curarg == '-')
+ {
+ if (strcmp(curarg, "-o") == 0 || strcmp(curarg, "--output") == 0)
+ outfilename = argv[++arg];
+ else if (strcmp(curarg, "-r") == 0 || strcmp(curarg, "--samplerate") == 0)
+ output_rate = atoi(argv[++arg]);
+ else
+ {
+ fprintf(stderr, "Unknown argument: %s\n", curarg);
+ argerr = true;
+ }
+ }
+ else
+ filename = curarg;
+ }
+
+ // if invalid syntax, show usage
+ if (argerr || filename == nullptr || outfilename == nullptr)
+ {
+ fprintf(stderr, "Usage: vgmrender <inputfile> -o <outputfile> [-r <rate>]\n");
+ return 1;
+ }
+
+ // attempt to read the file
+ FILE *file = fopen(filename, "rb");
+ if (file == nullptr)
+ {
+ fprintf(stderr, "Error opening file '%s'\n", filename);
+ return 2;
+ }
+
+ // get the length and create a buffer
+ fseek(file, 0, SEEK_END);
+ uint32_t size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+ std::vector<uint8_t> buffer(size);
+
+ // read the contents
+ auto bytes_read = fread(&buffer[0], 1, size, file);
+ if (bytes_read != size)
+ {
+ fprintf(stderr, "Error reading file contents\n");
+ return 3;
+ }
+ fclose(file);
+
+ // check for gzip-format
+ if (buffer.size() >= 10 && buffer[0] == 0x1f && buffer[1] == 0x8b && buffer[2] == 0x08)
+ {
+ // copy the raw data to a new buffer
+ std::vector<uint8_t> compressed = buffer;
+
+ // determine uncompressed size and resize the buffer
+ uint8_t *end = &compressed[compressed.size()];
+ uint32_t uncompressed = end[-4] | (end[-3] << 8) | (end[-2] << 16) | (end[-1] << 24);
+ if (size < compressed.size() || size > 32*1024*1024)
+ {
+ fprintf(stderr, "File '%s' appears to be a compressed file but has unexpected size of %d\n", filename, size);
+ return 4;
+ }
+ buffer.resize(uncompressed);
+
+ // decompress the data
+ auto result = em_inflate(&compressed[0], compressed.size(), &buffer[0], buffer.size());
+ if (result == -1)
+ {
+ fprintf(stderr, "Error decompressing data from file\n");
+ return 4;
+ }
+ }
+
+ // check the ID
+ uint32_t offset = 0;
+ if (buffer.size() < 64 || buffer[0] != 'V' || buffer[1] != 'g' || buffer[2] != 'm' || buffer[3] != ' ')
+ {
+ fprintf(stderr, "File '%s' does not appear to be a valid VGM file\n", filename);
+ return 4;
+ }
+
+ // parse the header, creating any chips needed
+ uint32_t data_start = parse_header(buffer);
+
+ // if no chips created, fail
+ if (active_chips.size() == 0)
+ {
+ fprintf(stderr, "No compatible chips found, exiting.\n");
+ return 5;
+ }
+
+ // generate the output
+ std::vector<int32_t> wav_buffer;
+ generate_all(buffer, data_start, output_rate, wav_buffer);
+
+ int err = write_wav(outfilename, output_rate, wav_buffer);
+
+#if (CAPTURE_NATIVE)
+ {
+ int chipnum = 0;
+ for (auto chip : active_chips)
+ if (err == 0 && chip->m_native_data.size() > 0)
+ {
+ char filename[20];
+ sprintf(filename, "native-%d.wav", chipnum++);
+ err = write_wav(filename, chip->sample_rate(), chip->m_native_data);
+ }
+ }
+#endif
+#if (RUN_NUKED_OPN2)
+ {
+ int chipnum = 0;
+ for (auto chip : active_chips)
+ if (err == 0 && chip->m_nuked_data.size() > 0)
+ {
+ char filename[20];
+ sprintf(filename, "nuked-%d.wav", chipnum++);
+ err = write_wav(filename, chip->sample_rate(), chip->m_nuked_data);
+ }
+ }
+#endif
+
+ return err;
+}
+
+#if (RUN_NUKED_OPN2)
+namespace nuked {
+#include "test/ym3438.c"
+}
+#endif
diff --git a/3rdparty/ymfm/src/ymfm.h b/3rdparty/ymfm/src/ymfm.h
new file mode 100644
index 00000000000..cba731d9afa
--- /dev/null
+++ b/3rdparty/ymfm/src/ymfm.h
@@ -0,0 +1,486 @@
+// BSD 3-Clause License
+//
+// Copyright (c) 2021, Aaron Giles
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef YMFM_H
+#define YMFM_H
+
+#pragma once
+
+#include <cassert>
+#include <cstdint>
+#include <cstdio>
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace ymfm
+{
+
+//*********************************************************
+// DEBUGGING
+//*********************************************************
+
+class debug
+{
+public:
+ // masks to help isolate specific channels
+ static constexpr uint32_t GLOBAL_FM_CHANNEL_MASK = 0xffffffff;
+ static constexpr uint32_t GLOBAL_ADPCM_A_CHANNEL_MASK = 0xffffffff;
+ static constexpr uint32_t GLOBAL_ADPCM_B_CHANNEL_MASK = 0xffffffff;
+ static constexpr uint32_t GLOBAL_PCM_CHANNEL_MASK = 0xffffffff;
+
+ // types of logging
+ static constexpr bool LOG_FM_WRITES = false;
+ static constexpr bool LOG_KEYON_EVENTS = false;
+ static constexpr bool LOG_UNEXPECTED_READ_WRITES = false;
+
+ // helpers to write based on the log type
+ template<typename... Params> static void log_fm_write(Params &&... args) { if (LOG_FM_WRITES) log(args...); }
+ template<typename... Params> static void log_keyon(Params &&... args) { if (LOG_KEYON_EVENTS) log(args...); }
+ template<typename... Params> static void log_unexpected_read_write(Params &&... args) { if (LOG_UNEXPECTED_READ_WRITES) log(args...); }
+
+ // downstream helper to output log data; defaults to printf
+ template<typename... Params> static void log(Params &&... args) { printf(args...); }
+};
+
+
+
+//*********************************************************
+// GLOBAL HELPERS
+//*********************************************************
+
+//-------------------------------------------------
+// bitfield - extract a bitfield from the given
+// value, starting at bit 'start' for a length of
+// 'length' bits
+//-------------------------------------------------
+
+inline uint32_t bitfield(uint32_t value, int start, int length = 1)
+{
+ return (value >> start) & ((1 << length) - 1);
+}
+
+
+//-------------------------------------------------
+// clamp - clamp between the minimum and maximum
+// values provided
+//-------------------------------------------------
+
+inline int32_t clamp(int32_t value, int32_t minval, int32_t maxval)
+{
+ if (value < minval)
+ return minval;
+ if (value > maxval)
+ return maxval;
+ return value;
+}
+
+
+//-------------------------------------------------
+// array_size - return the size of an array
+//-------------------------------------------------
+
+template<typename ArrayType, int ArraySize>
+constexpr uint32_t array_size(ArrayType (&array)[ArraySize])
+{
+ return ArraySize;
+}
+
+
+//-------------------------------------------------
+// count_leading_zeros - return the number of
+// leading zeros in a 32-bit value; CPU-optimized
+// versions for various architectures are included
+// below
+//-------------------------------------------------
+
+#if defined(__GNUC__)
+
+inline uint8_t count_leading_zeros(uint32_t value)
+{
+ if (value == 0)
+ return 32;
+ return __builtin_clz(value);
+}
+
+#elif defined(_MSC_VER)
+
+inline uint8_t count_leading_zeros(uint32_t value)
+{
+ unsigned long index;
+ return _BitScanReverse(&index, value) ? (31U - index) : 32U;
+}
+
+#else
+
+inline uint8_t count_leading_zeros(uint32_t value)
+{
+ if (value == 0)
+ return 32;
+ uint8_t count;
+ for (count = 0; int32_t(value) >= 0; count++)
+ value <<= 1;
+ return count;
+}
+
+#endif
+
+
+// Many of the Yamaha FM chips emit a floating-point value, which is sent to
+// a DAC for processing. The exact format of this floating-point value is
+// documented below. This description only makes sense if the "internal"
+// format treats sign as 1=positive and 0=negative, so the helpers below
+// presume that.
+//
+// Internal OPx data 16-bit signed data Exp Sign Mantissa
+// ================= ================= === ==== ========
+// 1 1xxxxxxxx------ -> 0 1xxxxxxxx------ -> 111 1 1xxxxxxx
+// 1 01xxxxxxxx----- -> 0 01xxxxxxxx----- -> 110 1 1xxxxxxx
+// 1 001xxxxxxxx---- -> 0 001xxxxxxxx---- -> 101 1 1xxxxxxx
+// 1 0001xxxxxxxx--- -> 0 0001xxxxxxxx--- -> 100 1 1xxxxxxx
+// 1 00001xxxxxxxx-- -> 0 00001xxxxxxxx-- -> 011 1 1xxxxxxx
+// 1 000001xxxxxxxx- -> 0 000001xxxxxxxx- -> 010 1 1xxxxxxx
+// 1 000000xxxxxxxxx -> 0 000000xxxxxxxxx -> 001 1 xxxxxxxx
+// 0 111111xxxxxxxxx -> 1 111111xxxxxxxxx -> 001 0 xxxxxxxx
+// 0 111110xxxxxxxx- -> 1 111110xxxxxxxx- -> 010 0 0xxxxxxx
+// 0 11110xxxxxxxx-- -> 1 11110xxxxxxxx-- -> 011 0 0xxxxxxx
+// 0 1110xxxxxxxx--- -> 1 1110xxxxxxxx--- -> 100 0 0xxxxxxx
+// 0 110xxxxxxxx---- -> 1 110xxxxxxxx---- -> 101 0 0xxxxxxx
+// 0 10xxxxxxxx----- -> 1 10xxxxxxxx----- -> 110 0 0xxxxxxx
+// 0 0xxxxxxxx------ -> 1 0xxxxxxxx------ -> 111 0 0xxxxxxx
+
+//-------------------------------------------------
+// encode_fp - given a 32-bit signed input value
+// convert it to a signed 3.10 floating-point
+// value
+//-------------------------------------------------
+
+inline int16_t encode_fp(int32_t value)
+{
+ // handle overflows first
+ if (value < -32768)
+ return (7 << 10) | 0x000;
+ if (value > 32767)
+ return (7 << 10) | 0x3ff;
+
+ // we need to count the number of leading sign bits after the sign
+ // we can use count_leading_zeros if we invert negative values
+ int32_t scanvalue = value ^ (int32_t(value) >> 31);
+
+ // exponent is related to the number of leading bits starting from bit 14
+ int exponent = 7 - count_leading_zeros(scanvalue << 17);
+
+ // smallest exponent value allowed is 1
+ exponent = std::max(exponent, 1);
+
+ // mantissa
+ int32_t mantissa = value >> (exponent - 1);
+
+ // assemble into final form, inverting the sign
+ return ((exponent << 10) | (mantissa & 0x3ff)) ^ 0x200;
+}
+
+
+//-------------------------------------------------
+// decode_fp - given a 3.10 floating-point value,
+// convert it to a signed 16-bit value
+//-------------------------------------------------
+
+inline int16_t decode_fp(int16_t value)
+{
+ // invert the sign and the exponent
+ value ^= 0x1e00;
+
+ // shift mantissa up to 16 bits then apply inverted exponent
+ return int16_t(value << 6) >> bitfield(value, 10, 3);
+}
+
+
+//-------------------------------------------------
+// roundtrip_fp - compute the result of a round
+// trip through the encode/decode process above
+//-------------------------------------------------
+
+inline int16_t roundtrip_fp(int32_t value)
+{
+ // handle overflows first
+ if (value < -32768)
+ return -32768;
+ if (value > 32767)
+ return 32767;
+
+ // we need to count the number of leading sign bits after the sign
+ // we can use count_leading_zeros if we invert negative values
+ int32_t scanvalue = value ^ (int32_t(value) >> 31);
+
+ // exponent is related to the number of leading bits starting from bit 14
+ int exponent = 7 - count_leading_zeros(scanvalue << 17);
+
+ // smallest exponent value allowed is 1
+ exponent = std::max(exponent, 1);
+
+ // apply the shift back and forth to zero out bits that are lost
+ exponent -= 1;
+ return (value >> exponent) << exponent;
+}
+
+
+
+//*********************************************************
+// HELPER CLASSES
+//*********************************************************
+
+// various envelope states
+enum envelope_state : uint32_t
+{
+ EG_DEPRESS = 0, // OPLL only; set EG_HAS_DEPRESS to enable
+ EG_ATTACK = 1,
+ EG_DECAY = 2,
+ EG_SUSTAIN = 3,
+ EG_RELEASE = 4,
+ EG_REVERB = 5, // OPQ/OPZ only; set EG_HAS_REVERB to enable
+ EG_STATES = 6
+};
+
+// external I/O access classes
+enum access_class : uint32_t
+{
+ ACCESS_IO = 0,
+ ACCESS_ADPCM_A,
+ ACCESS_ADPCM_B,
+ ACCESS_PCM,
+ ACCESS_CLASSES
+};
+
+
+
+//*********************************************************
+// HELPER CLASSES
+//*********************************************************
+
+// ======================> ymfm_output
+
+// struct containing an array of output values
+template<int NumOutputs>
+struct ymfm_output
+{
+ // clear all outputs to 0
+ ymfm_output &clear()
+ {
+ for (uint32_t index = 0; index < NumOutputs; index++)
+ data[index] = 0;
+ return *this;
+ }
+
+ // clamp all outputs to a 16-bit signed value
+ ymfm_output &clamp16()
+ {
+ for (uint32_t index = 0; index < NumOutputs; index++)
+ data[index] = clamp(data[index], -32768, 32767);
+ return *this;
+ }
+
+ // run each output value through the floating-point processor
+ ymfm_output &roundtrip_fp()
+ {
+ for (uint32_t index = 0; index < NumOutputs; index++)
+ data[index] = ymfm::roundtrip_fp(data[index]);
+ return *this;
+ }
+
+ // internal state
+ int32_t data[NumOutputs];
+};
+
+
+// ======================> ymfm_saved_state
+
+// this class contains a managed vector of bytes that is used to save and
+// restore state
+class ymfm_saved_state
+{
+public:
+ // construction
+ ymfm_saved_state(std::vector<uint8_t> &buffer, bool saving) :
+ m_buffer(buffer),
+ m_offset(saving ? -1 : 0)
+ {
+ if (saving)
+ buffer.resize(0);
+ }
+
+ // are we saving or restoring?
+ bool saving() const { return (m_offset < 0); }
+
+ // generic save/restore
+ template<typename DataType>
+ void save_restore(DataType &data)
+ {
+ if (saving())
+ save(data);
+ else
+ restore(data);
+ }
+
+public:
+ // save data to the buffer
+ void save(bool &data) { write(data ? 1 : 0); }
+ void save(int8_t &data) { write(data); }
+ void save(uint8_t &data) { write(data); }
+ void save(int16_t &data) { write(data).write(data >> 8); }
+ void save(uint16_t &data) { write(data).write(data >> 8); }
+ void save(int32_t &data) { write(data).write(data >> 8).write(data >> 16).write(data >> 24); }
+ void save(uint32_t &data) { write(data).write(data >> 8).write(data >> 16).write(data >> 24); }
+ void save(envelope_state &data) { write(uint8_t(data)); }
+ template<typename DataType, int Count>
+ void save(DataType (&data)[Count]) { for (uint32_t index = 0; index < Count; index++) save(data[index]); }
+
+ // restore data from the buffer
+ void restore(bool &data) { data = read() ? true : false; }
+ void restore(int8_t &data) { data = read(); }
+ void restore(uint8_t &data) { data = read(); }
+ void restore(int16_t &data) { data = read(); data |= read() << 8; }
+ void restore(uint16_t &data) { data = read(); data |= read() << 8; }
+ void restore(int32_t &data) { data = read(); data |= read() << 8; data |= read() << 16; data |= read() << 24; }
+ void restore(uint32_t &data) { data = read(); data |= read() << 8; data |= read() << 16; data |= read() << 24; }
+ void restore(envelope_state &data) { data = envelope_state(read()); }
+ template<typename DataType, int Count>
+ void restore(DataType (&data)[Count]) { for (uint32_t index = 0; index < Count; index++) restore(data[index]); }
+
+ // internal helper
+ ymfm_saved_state &write(uint8_t data) { m_buffer.push_back(data); return *this; }
+ uint8_t read() { return (m_offset < int32_t(m_buffer.size())) ? m_buffer[m_offset++] : 0; }
+
+ // internal state
+ std::vector<uint8_t> &m_buffer;
+ int32_t m_offset;
+};
+
+
+
+//*********************************************************
+// INTERFACE CLASSES
+//*********************************************************
+
+// ======================> ymfm_engine_callbacks
+
+// this class represents functions in the engine that the ymfm_interface
+// needs to be able to call; it is represented here as a separate interface
+// that is independent of the actual engine implementation
+class ymfm_engine_callbacks
+{
+public:
+ // timer callback; called by the interface when a timer fires
+ virtual void engine_timer_expired(uint32_t tnum) = 0;
+
+ // check interrupts; called by the interface after synchronization
+ virtual void engine_check_interrupts() = 0;
+
+ // mode register write; called by the interface after synchronization
+ virtual void engine_mode_write(uint8_t data) = 0;
+};
+
+
+// ======================> ymfm_interface
+
+// this class represents the interface between the fm_engine and the outside
+// world; it provides hooks for timers, synchronization, and I/O
+class ymfm_interface
+{
+ // the engine is our friend
+ template<typename RegisterType> friend class fm_engine_base;
+
+public:
+ // the following functions must be implemented by any derived classes; the
+ // default implementations are sufficient for some minimal operation, but will
+ // likely need to be overridden to integrate with the outside world; they are
+ // all prefixed with ymfm_ to reduce the likelihood of namespace collisions
+
+ //
+ // timing and synchronizaton
+ //
+
+ // the chip implementation calls this when a write happens to the mode
+ // register, which could affect timers and interrupts; our responsibility
+ // is to ensure the system is up to date before calling the engine's
+ // engine_mode_write() method
+ virtual void ymfm_sync_mode_write(uint8_t data) { m_engine->engine_mode_write(data); }
+
+ // the chip implementation calls this when the chip's status has changed,
+ // which may affect the interrupt state; our responsibility is to ensure
+ // the system is up to date before calling the engine's
+ // engine_check_interrupts() method
+ virtual void ymfm_sync_check_interrupts() { m_engine->engine_check_interrupts(); }
+
+ // the chip implementation calls this when one of the two internal timers
+ // has changed state; our responsibility is to arrange to call the engine's
+ // engine_timer_expired() method after the provided number of clocks; if
+ // duration_in_clocks is negative, we should cancel any outstanding timers
+ virtual void ymfm_set_timer(uint32_t tnum, int32_t duration_in_clocks) { }
+
+ // the chip implementation calls this to indicate that the chip should be
+ // considered in a busy state until the given number of clocks has passed;
+ // our responsibility is to compute and remember the ending time based on
+ // the chip's clock for later checking
+ virtual void ymfm_set_busy_end(uint32_t clocks) { }
+
+ // the chip implementation calls this to see if the chip is still currently
+ // is a busy state, as specified by a previous call to ymfm_set_busy_end();
+ // our responsibility is to compare the current time against the previously
+ // noted busy end time and return true if we haven't yet passed it
+ virtual bool ymfm_is_busy() { return false; }
+
+ //
+ // I/O functions
+ //
+
+ // the chip implementation calls this when the state of the IRQ signal has
+ // changed due to a status change; our responsibility is to respond as
+ // needed to the change in IRQ state, signaling any consumers
+ virtual void ymfm_update_irq(bool asserted) { }
+
+ // the chip implementation calls this whenever data is read from outside
+ // of the chip; our responsibility is to provide the data requested
+ virtual uint8_t ymfm_external_read(access_class type, uint32_t address) { return 0; }
+
+ // the chip implementation calls this whenever data is written outside
+ // of the chip; our responsibility is to pass the written data on to any consumers
+ virtual void ymfm_external_write(access_class type, uint32_t address, uint8_t data) { }
+
+protected:
+ // pointer to engine callbacks -- this is set directly by the engine at
+ // construction time
+ ymfm_engine_callbacks *m_engine;
+};
+
+}
+
+#endif // YMFM_H
diff --git a/src/devices/sound/ymadpcm.cpp b/3rdparty/ymfm/src/ymfm_adpcm.cpp
index c8dd5df0cca..882dcf3de7c 100644
--- a/src/devices/sound/ymadpcm.cpp
+++ b/3rdparty/ymfm/src/ymfm_adpcm.cpp
@@ -1,44 +1,47 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-
-#include "emu.h"
-#include "ymadpcm.h"
-
-#define VERBOSE 1
-#define LOG_OUTPUT_FUNC osd_printf_verbose
-#include "logmacro.h"
-
-
-//*********************************************************
-// MACROS
-//*********************************************************
-
-// special naming helper to keep our namespace isolated from other
-// same-named objects in the device's namespace
-#define ADPCM_A_NAME(x) x, "adpcma." #x
-#define ADPCM_B_NAME(x) x, "adpcmb." #x
-
-
+// BSD 3-Clause License
+//
+// Copyright (c) 2021, Aaron Giles
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "ymfm_adpcm.h"
+
+namespace ymfm
+{
//*********************************************************
// ADPCM "A" REGISTERS
//*********************************************************
//-------------------------------------------------
-// ymadpcm_a_registers - constructor
-//-------------------------------------------------
-
-void ymadpcm_a_registers::save(device_t &device)
-{
- device.save_item(ADPCM_A_NAME(m_regdata));
-}
-
-
-//-------------------------------------------------
// reset - reset the register state
//-------------------------------------------------
-void ymadpcm_a_registers::reset()
+void adpcm_a_registers::reset()
{
std::fill_n(&m_regdata[0], REGISTERS, 0);
@@ -49,15 +52,25 @@ void ymadpcm_a_registers::reset()
}
+//-------------------------------------------------
+// save_restore - save or restore the data
+//-------------------------------------------------
+
+void adpcm_a_registers::save_restore(ymfm_saved_state &state)
+{
+ state.save_restore(m_regdata);
+}
+
+
//*********************************************************
// ADPCM "A" CHANNEL
//*********************************************************
//-------------------------------------------------
-// ymadpcm_a_channel - constructor
+// adpcm_a_channel - constructor
//-------------------------------------------------
-ymadpcm_a_channel::ymadpcm_a_channel(ymadpcm_a_engine &owner, u32 choffs, read8sm_delegate reader, u32 addrshift) :
+adpcm_a_channel::adpcm_a_channel(adpcm_a_engine &owner, uint32_t choffs, uint32_t addrshift) :
m_choffs(choffs),
m_address_shift(addrshift),
m_playing(0),
@@ -66,32 +79,17 @@ ymadpcm_a_channel::ymadpcm_a_channel(ymadpcm_a_engine &owner, u32 choffs, read8s
m_curaddress(0),
m_accumulator(0),
m_step_index(0),
- m_reader(std::move(reader)),
- m_regs(owner.regs())
+ m_regs(owner.regs()),
+ m_owner(owner)
{
}
//-------------------------------------------------
-// save - register for save states
-//-------------------------------------------------
-
-void ymadpcm_a_channel::save(device_t &device, u32 index)
-{
- device.save_item(ADPCM_A_NAME(m_playing), index);
- device.save_item(ADPCM_A_NAME(m_curnibble), index);
- device.save_item(ADPCM_A_NAME(m_curbyte), index);
- device.save_item(ADPCM_A_NAME(m_curaddress), index);
- device.save_item(ADPCM_A_NAME(m_accumulator), index);
- device.save_item(ADPCM_A_NAME(m_step_index), index);
-}
-
-
-//-------------------------------------------------
// reset - reset the channel state
//-------------------------------------------------
-void ymadpcm_a_channel::reset()
+void adpcm_a_channel::reset()
{
m_playing = 0;
m_curnibble = 0;
@@ -103,10 +101,25 @@ void ymadpcm_a_channel::reset()
//-------------------------------------------------
+// save_restore - save or restore the data
+//-------------------------------------------------
+
+void adpcm_a_channel::save_restore(ymfm_saved_state &state)
+{
+ state.save_restore(m_playing);
+ state.save_restore(m_curnibble);
+ state.save_restore(m_curbyte);
+ state.save_restore(m_curaddress);
+ state.save_restore(m_accumulator);
+ state.save_restore(m_step_index);
+}
+
+
+//-------------------------------------------------
// keyonoff - signal key on/off
//-------------------------------------------------
-void ymadpcm_a_channel::keyonoff(bool on)
+void adpcm_a_channel::keyonoff(bool on)
{
// QUESTION: repeated key ons restart the sample?
m_playing = on;
@@ -117,13 +130,16 @@ void ymadpcm_a_channel::keyonoff(bool on)
m_curbyte = 0;
m_accumulator = 0;
m_step_index = 0;
- LOG("KeyOn ADPCM-A%d: pan=%d%d start=%04X end=%04X level=%02X\n",
- m_choffs,
- m_regs.ch_pan_left(m_choffs),
- m_regs.ch_pan_right(m_choffs),
- m_regs.ch_start(m_choffs),
- m_regs.ch_end(m_choffs),
- m_regs.ch_instrument_level(m_choffs));
+
+ // don't log masked channels
+ if (((debug::GLOBAL_ADPCM_A_CHANNEL_MASK >> m_choffs) & 1) != 0)
+ debug::log_keyon("KeyOn ADPCM-A%d: pan=%d%d start=%04X end=%04X level=%02X\n",
+ m_choffs,
+ m_regs.ch_pan_left(m_choffs),
+ m_regs.ch_pan_right(m_choffs),
+ m_regs.ch_start(m_choffs),
+ m_regs.ch_end(m_choffs),
+ m_regs.ch_instrument_level(m_choffs));
}
}
@@ -132,7 +148,7 @@ void ymadpcm_a_channel::keyonoff(bool on)
// clock - master clocking function
//-------------------------------------------------
-bool ymadpcm_a_channel::clock()
+bool adpcm_a_channel::clock()
{
// if not playing, just output 0
if (m_playing == 0)
@@ -141,18 +157,21 @@ bool ymadpcm_a_channel::clock()
return false;
}
- // stop when we hit the end address
- if ((m_curaddress >> m_address_shift) >= m_regs.ch_end(m_choffs))
+ // stop when we hit the end address; apparently only low 20 bits are used for
+ // comparison on the YM2610: this affects sample playback in some games, for
+ // example twinspri character select screen music will skip some samples if
+ // this is not correct
+ if (((m_curaddress ^ (m_regs.ch_end(m_choffs) << m_address_shift)) & 0xfffff) == 0)
{
m_playing = m_accumulator = 0;
return true;
}
// if we're about to read nibble 0, fetch the data
- u8 data;
+ uint8_t data;
if (m_curnibble == 0)
{
- m_curbyte = m_reader(m_curaddress++);
+ m_curbyte = m_owner.intf().ymfm_external_read(ACCESS_ADPCM_A, m_curaddress++);
data = m_curbyte >> 4;
m_curnibble = 1;
}
@@ -165,7 +184,7 @@ bool ymadpcm_a_channel::clock()
}
// compute the ADPCM delta
- static u16 const s_steps[49] =
+ static uint16_t const s_steps[49] =
{
16, 17, 19, 21, 23, 25, 28,
31, 34, 37, 41, 45, 50, 55,
@@ -175,16 +194,16 @@ bool ymadpcm_a_channel::clock()
449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552
};
- s32 delta = (2 * BIT(data, 0, 3) + 1) * s_steps[m_step_index] / 8;
- if (BIT(data, 3))
+ int32_t delta = (2 * bitfield(data, 0, 3) + 1) * s_steps[m_step_index] / 8;
+ if (bitfield(data, 3))
delta = -delta;
// the 12-bit accumulator wraps on the ym2610 and ym2608 (like the msm5205)
m_accumulator = (m_accumulator + delta) & 0xfff;
// adjust ADPCM step
- static s8 const s_step_inc[8] = { -1, -1, -1, -1, 2, 5, 7, 9 };
- m_step_index = std::clamp(m_step_index + s_step_inc[BIT(data, 0, 3)], 0, 48);
+ static int8_t const s_step_inc[8] = { -1, -1, -1, -1, 2, 5, 7, 9 };
+ m_step_index = clamp(m_step_index + s_step_inc[bitfield(data, 0, 3)], 0, 48);
return false;
}
@@ -195,9 +214,10 @@ bool ymadpcm_a_channel::clock()
// panning applied
//-------------------------------------------------
-void ymadpcm_a_channel::output(s32 outputs[2]) const
+template<int NumOutputs>
+void adpcm_a_channel::output(ymfm_output<NumOutputs> &output) const
{
- // volume combined instrument and total levels
+ // volume combines instrument and total levels
int vol = (m_regs.ch_instrument_level(m_choffs) ^ 0x1f) + (m_regs.total_level() ^ 0x3f);
// if combined is maximum, don't add to outputs
@@ -206,18 +226,18 @@ void ymadpcm_a_channel::output(s32 outputs[2]) const
// convert into a shift and a multiplier
// QUESTION: verify this from other sources
- s8 mul = 15 - (vol & 7);
- u8 shift = 4 + 1 + (vol >> 3);
+ int8_t mul = 15 - (vol & 7);
+ uint8_t shift = 4 + 1 + (vol >> 3);
// m_accumulator is a 12-bit value; shift up to sign-extend;
// the downshift is incorporated into 'shift'
- s16 value = ((s16(m_accumulator << 4) * mul) >> shift) & ~3;
+ int16_t value = ((int16_t(m_accumulator << 4) * mul) >> shift) & ~3;
// apply to left/right as appropriate
- if (m_regs.ch_pan_left(m_choffs))
- outputs[0] += value;
- if (m_regs.ch_pan_right(m_choffs))
- outputs[1] += value;
+ if (NumOutputs == 1 || m_regs.ch_pan_left(m_choffs))
+ output.data[0] += value;
+ if (NumOutputs > 1 && m_regs.ch_pan_right(m_choffs))
+ output.data[1] += value;
}
@@ -227,44 +247,45 @@ void ymadpcm_a_channel::output(s32 outputs[2]) const
//*********************************************************
//-------------------------------------------------
-// ymadpcm_a_engine - constructor
+// adpcm_a_engine - constructor
//-------------------------------------------------
-ymadpcm_a_engine::ymadpcm_a_engine(device_t &device, read8sm_delegate reader, u32 addrshift)
+adpcm_a_engine::adpcm_a_engine(ymfm_interface &intf, uint32_t addrshift) :
+ m_intf(intf)
{
// create the channels
for (int chnum = 0; chnum < CHANNELS; chnum++)
- m_channel[chnum] = std::make_unique<ymadpcm_a_channel>(*this, chnum, reader, addrshift);
+ m_channel[chnum] = std::make_unique<adpcm_a_channel>(*this, chnum, addrshift);
}
//-------------------------------------------------
-// save - register for save states
+// reset - reset the engine state
//-------------------------------------------------
-void ymadpcm_a_engine::save(device_t &device)
+void adpcm_a_engine::reset()
{
- // save register state
- m_regs.save(device);
+ // reset register state
+ m_regs.reset();
- // save channel state
- for (int chnum = 0; chnum < std::size(m_channel); chnum++)
- m_channel[chnum]->save(device, chnum);
+ // reset each channel
+ for (auto &chan : m_channel)
+ chan->reset();
}
//-------------------------------------------------
-// reset - reset the engine state
+// save_restore - save or restore the data
//-------------------------------------------------
-void ymadpcm_a_engine::reset()
+void adpcm_a_engine::save_restore(ymfm_saved_state &state)
{
- // reset register state
- m_regs.reset();
+ // save register state
+ m_regs.save_restore(state);
- // reset each channel
- for (auto &chan : m_channel)
- chan->reset();
+ // save channel state
+ for (int chnum = 0; chnum < CHANNELS; chnum++)
+ m_channel[chnum]->save_restore(state);
}
@@ -272,12 +293,12 @@ void ymadpcm_a_engine::reset()
// clock - master clocking function
//-------------------------------------------------
-u32 ymadpcm_a_engine::clock(u32 chanmask)
+uint32_t adpcm_a_engine::clock(uint32_t chanmask)
{
// clock each channel, setting a bit in result if it finished
- u32 result = 0;
- for (int chnum = 0; chnum < std::size(m_channel); chnum++)
- if (BIT(chanmask, chnum))
+ uint32_t result = 0;
+ for (int chnum = 0; chnum < CHANNELS; chnum++)
+ if (bitfield(chanmask, chnum))
if (m_channel[chnum]->clock())
result |= 1 << chnum;
@@ -290,20 +311,27 @@ u32 ymadpcm_a_engine::clock(u32 chanmask)
// update - master update function
//-------------------------------------------------
-void ymadpcm_a_engine::output(s32 outputs[2], u32 chanmask)
+template<int NumOutputs>
+void adpcm_a_engine::output(ymfm_output<NumOutputs> &output, uint32_t chanmask)
{
+ // mask out some channels for debug purposes
+ chanmask &= debug::GLOBAL_ADPCM_A_CHANNEL_MASK;
+
// compute the output of each channel
- for (int chnum = 0; chnum < std::size(m_channel); chnum++)
- if (BIT(chanmask, chnum))
- m_channel[chnum]->output(outputs);
+ for (int chnum = 0; chnum < CHANNELS; chnum++)
+ if (bitfield(chanmask, chnum))
+ m_channel[chnum]->output(output);
}
+template void adpcm_a_engine::output<1>(ymfm_output<1> &output, uint32_t chanmask);
+template void adpcm_a_engine::output<2>(ymfm_output<2> &output, uint32_t chanmask);
+
//-------------------------------------------------
// write - handle writes to the ADPCM-A registers
//-------------------------------------------------
-void ymadpcm_a_engine::write(u32 regnum, u8 data)
+void adpcm_a_engine::write(uint32_t regnum, uint8_t data)
{
// store the raw value to the register array;
// most writes are passive, consumed only when needed
@@ -311,9 +339,9 @@ void ymadpcm_a_engine::write(u32 regnum, u8 data)
// actively handle writes to the control register
if (regnum == 0x00)
- for (int chnum = 0; chnum < std::size(m_channel); chnum++)
- if (BIT(data, chnum))
- m_channel[chnum]->keyonoff(BIT(~data, 7));
+ for (int chnum = 0; chnum < CHANNELS; chnum++)
+ if (bitfield(data, chnum))
+ m_channel[chnum]->keyonoff(bitfield(~data, 7));
}
@@ -323,37 +351,38 @@ void ymadpcm_a_engine::write(u32 regnum, u8 data)
//*********************************************************
//-------------------------------------------------
-// ymadpcm_b_registers - constructor
+// reset - reset the register state
//-------------------------------------------------
-void ymadpcm_b_registers::save(device_t &device)
+void adpcm_b_registers::reset()
{
- device.save_item(ADPCM_B_NAME(m_regdata));
+ std::fill_n(&m_regdata[0], REGISTERS, 0);
+
+ // default limit to wide open
+ m_regdata[0x0c] = m_regdata[0x0d] = 0xff;
}
//-------------------------------------------------
-// reset - reset the register state
+// save_restore - save or restore the data
//-------------------------------------------------
-void ymadpcm_b_registers::reset()
+void adpcm_b_registers::save_restore(ymfm_saved_state &state)
{
- std::fill_n(&m_regdata[0], REGISTERS, 0);
-
- // default limit to wide open
- m_regdata[0x0c] = m_regdata[0x0d] = 0xff;
+ state.save_restore(m_regdata);
}
+
//*********************************************************
// ADPCM "B" CHANNEL
//*********************************************************
//-------------------------------------------------
-// ymadpcm_b_channel - constructor
+// adpcm_b_channel - constructor
//-------------------------------------------------
-ymadpcm_b_channel::ymadpcm_b_channel(ymadpcm_b_engine &owner, read8sm_delegate reader, write8sm_delegate writer, u32 addrshift) :
+adpcm_b_channel::adpcm_b_channel(adpcm_b_engine &owner, uint32_t addrshift) :
m_address_shift(addrshift),
m_status(STATUS_BRDY),
m_curnibble(0),
@@ -364,36 +393,17 @@ ymadpcm_b_channel::ymadpcm_b_channel(ymadpcm_b_engine &owner, read8sm_delegate r
m_accumulator(0),
m_prev_accum(0),
m_adpcm_step(STEP_MIN),
- m_reader(reader),
- m_writer(writer),
- m_regs(owner.regs())
+ m_regs(owner.regs()),
+ m_owner(owner)
{
}
//-------------------------------------------------
-// save - register for save states
-//-------------------------------------------------
-
-void ymadpcm_b_channel::save(device_t &device, u32 index)
-{
- device.save_item(ADPCM_B_NAME(m_status), index);
- device.save_item(ADPCM_B_NAME(m_curnibble), index);
- device.save_item(ADPCM_B_NAME(m_curbyte), index);
- device.save_item(ADPCM_B_NAME(m_dummy_read), index);
- device.save_item(ADPCM_B_NAME(m_position), index);
- device.save_item(ADPCM_B_NAME(m_curaddress), index);
- device.save_item(ADPCM_B_NAME(m_accumulator), index);
- device.save_item(ADPCM_B_NAME(m_prev_accum), index);
- device.save_item(ADPCM_B_NAME(m_adpcm_step), index);
-}
-
-
-//-------------------------------------------------
// reset - reset the channel state
//-------------------------------------------------
-void ymadpcm_b_channel::reset()
+void adpcm_b_channel::reset()
{
m_status = STATUS_BRDY;
m_curnibble = 0;
@@ -408,10 +418,28 @@ void ymadpcm_b_channel::reset()
//-------------------------------------------------
+// save_restore - save or restore the data
+//-------------------------------------------------
+
+void adpcm_b_channel::save_restore(ymfm_saved_state &state)
+{
+ state.save_restore(m_status);
+ state.save_restore(m_curnibble);
+ state.save_restore(m_curbyte);
+ state.save_restore(m_dummy_read);
+ state.save_restore(m_position);
+ state.save_restore(m_curaddress);
+ state.save_restore(m_accumulator);
+ state.save_restore(m_prev_accum);
+ state.save_restore(m_adpcm_step);
+}
+
+
+//-------------------------------------------------
// clock - master clocking function
//-------------------------------------------------
-void ymadpcm_b_channel::clock()
+void adpcm_b_channel::clock()
{
// only process if active and not recording (which we don't support)
if (!m_regs.execute() || m_regs.record() || (m_status & STATUS_PLAYING) == 0)
@@ -421,8 +449,8 @@ void ymadpcm_b_channel::clock()
}
// otherwise, advance the step
- u32 position = m_position + m_regs.delta_n();
- m_position = u16(position);
+ uint32_t position = m_position + m_regs.delta_n();
+ m_position = uint16_t(position);
if (position < 0x10000)
return;
@@ -446,7 +474,7 @@ void ymadpcm_b_channel::clock()
m_accumulator = 0;
m_prev_accum = 0;
m_status = (m_status & ~STATUS_PLAYING) | STATUS_EOS;
- LOG("ADPCM EOS\n");
+ debug::log_keyon("%s\n", "ADPCM EOS");
return;
}
}
@@ -454,13 +482,13 @@ void ymadpcm_b_channel::clock()
// if we're about to process nibble 0, fetch and increment
if (m_curnibble == 0)
{
- m_curbyte = m_reader(m_curaddress++);
+ m_curbyte = m_owner.intf().ymfm_external_read(ACCESS_ADPCM_B, m_curaddress++);
m_curaddress &= 0xffffff;
}
}
// extract the nibble from our current byte
- u8 data = u8(m_curbyte << (4 * m_curnibble)) >> 4;
+ uint8_t data = uint8_t(m_curbyte << (4 * m_curnibble)) >> 4;
m_curnibble ^= 1;
// if CPU-driven and we just processed the last nibble, copy the next byte and request more
@@ -474,16 +502,16 @@ void ymadpcm_b_channel::clock()
m_prev_accum = m_accumulator;
// forecast to next forecast: 1/8, 3/8, 5/8, 7/8, 9/8, 11/8, 13/8, 15/8
- s32 delta = (2 * BIT(data, 0, 3) + 1) * m_adpcm_step / 8;
- if (BIT(data, 3))
+ int32_t delta = (2 * bitfield(data, 0, 3) + 1) * m_adpcm_step / 8;
+ if (bitfield(data, 3))
delta = -delta;
// add and clamp to 16 bits
- m_accumulator = std::clamp(m_accumulator + delta, -32768, 32767);
+ m_accumulator = clamp(m_accumulator + delta, -32768, 32767);
// scale the ADPCM step: 0.9, 0.9, 0.9, 0.9, 1.2, 1.6, 2.0, 2.4
- static u8 const s_step_scale[8] = { 57, 57, 57, 57, 77, 102, 128, 153 };
- m_adpcm_step = std::clamp((m_adpcm_step * s_step_scale[BIT(data, 0, 3)]) / 64, STEP_MIN, STEP_MAX);
+ static uint8_t const s_step_scale[8] = { 57, 57, 57, 57, 77, 102, 128, 153 };
+ m_adpcm_step = clamp((m_adpcm_step * s_step_scale[bitfield(data, 0, 3)]) / 64, STEP_MIN, STEP_MAX);
}
@@ -492,19 +520,24 @@ void ymadpcm_b_channel::clock()
// panning applied
//-------------------------------------------------
-void ymadpcm_b_channel::output(s32 outputs[2], u32 rshift) const
+template<int NumOutputs>
+void adpcm_b_channel::output(ymfm_output<NumOutputs> &output, uint32_t rshift) const
{
+ // mask out some channels for debug purposes
+ if ((debug::GLOBAL_ADPCM_B_CHANNEL_MASK & 1) == 0)
+ return;
+
// do a linear interpolation between samples
- s32 result = (m_prev_accum * s32((m_position ^ 0xffff) + 1) + m_accumulator * s32(m_position)) >> 16;
+ int32_t result = (m_prev_accum * int32_t((m_position ^ 0xffff) + 1) + m_accumulator * int32_t(m_position)) >> 16;
// apply volume (level) in a linear fashion and reduce
- result = (result * s32(m_regs.level())) >> (8 + rshift);
+ result = (result * int32_t(m_regs.level())) >> (8 + rshift);
// apply to left/right
- if (m_regs.pan_left())
- outputs[0] += result;
- if (m_regs.pan_right())
- outputs[1] += result;
+ if (NumOutputs == 1 || m_regs.pan_left())
+ output.data[0] += result;
+ if (NumOutputs > 1 && m_regs.pan_right())
+ output.data[1] += result;
}
@@ -512,9 +545,9 @@ void ymadpcm_b_channel::output(s32 outputs[2], u32 rshift) const
// read - handle special register reads
//-------------------------------------------------
-u8 ymadpcm_b_channel::read(u32 regnum)
+uint8_t adpcm_b_channel::read(uint32_t regnum)
{
- u8 result = 0;
+ uint8_t result = 0;
// register 8 reads over the bus under some conditions
if (regnum == 0x08 && !m_regs.execute() && !m_regs.record() && m_regs.external())
@@ -530,13 +563,13 @@ u8 ymadpcm_b_channel::read(u32 regnum)
if (at_end())
{
m_status = STATUS_EOS | STATUS_BRDY;
- LOG("ADPCM EOS\n");
+ debug::log_keyon("%s\n", "ADPCM EOS");
}
// otherwise, write the data and signal ready
else
{
- result = m_reader(m_curaddress++);
+ result = m_owner.intf().ymfm_external_read(ACCESS_ADPCM_B, m_curaddress++);
m_status = STATUS_BRDY;
}
}
@@ -548,7 +581,7 @@ u8 ymadpcm_b_channel::read(u32 regnum)
// write - handle special register writes
//-------------------------------------------------
-void ymadpcm_b_channel::write(u32 regnum, u8 value)
+void adpcm_b_channel::write(uint32_t regnum, uint8_t value)
{
// register 0 can do a reset; also use writes here to reset the
// dummy read counter
@@ -557,22 +590,25 @@ void ymadpcm_b_channel::write(u32 regnum, u8 value)
if (m_regs.execute())
{
load_start();
- LOG("KeyOn ADPCM-B: rep=%d spk=%d pan=%d%d dac=%d 8b=%d rom=%d ext=%d rec=%d start=%04X end=%04X pre=%04X dn=%04X lvl=%02X lim=%04X\n",
- m_regs.repeat(),
- m_regs.speaker(),
- m_regs.pan_left(),
- m_regs.pan_right(),
- m_regs.dac_enable(),
- m_regs.dram_8bit(),
- m_regs.rom_ram(),
- m_regs.external(),
- m_regs.record(),
- m_regs.start(),
- m_regs.end(),
- m_regs.prescale(),
- m_regs.delta_n(),
- m_regs.level(),
- m_regs.limit());
+
+ // don't log masked channels
+ if ((debug::GLOBAL_ADPCM_B_CHANNEL_MASK & 1) != 0)
+ debug::log_keyon("KeyOn ADPCM-B: rep=%d spk=%d pan=%d%d dac=%d 8b=%d rom=%d ext=%d rec=%d start=%04X end=%04X pre=%04X dn=%04X lvl=%02X lim=%04X\n",
+ m_regs.repeat(),
+ m_regs.speaker(),
+ m_regs.pan_left(),
+ m_regs.pan_right(),
+ m_regs.dac_enable(),
+ m_regs.dram_8bit(),
+ m_regs.rom_ram(),
+ m_regs.external(),
+ m_regs.record(),
+ m_regs.start(),
+ m_regs.end(),
+ m_regs.prescale(),
+ m_regs.delta_n(),
+ m_regs.level(),
+ m_regs.limit());
}
else
m_status &= ~STATUS_EOS;
@@ -602,14 +638,14 @@ void ymadpcm_b_channel::write(u32 regnum, u8 value)
// did we hit the end? if so, signal EOS
if (at_end())
{
- LOG("ADPCM EOS\n");
+ debug::log_keyon("%s\n", "ADPCM EOS");
m_status = STATUS_EOS | STATUS_BRDY;
}
// otherwise, write the data and signal ready
else
{
- m_writer(m_curaddress++, value);
+ m_owner.intf().ymfm_external_write(ACCESS_ADPCM_B, m_curaddress++, value);
m_status = STATUS_BRDY;
}
}
@@ -622,7 +658,7 @@ void ymadpcm_b_channel::write(u32 regnum, u8 value)
// shift amount based on register settings
//-------------------------------------------------
-u32 ymadpcm_b_channel::address_shift() const
+uint32_t adpcm_b_channel::address_shift() const
{
// if a constant address shift, just provide that
if (m_address_shift != 0)
@@ -644,7 +680,7 @@ u32 ymadpcm_b_channel::address_shift() const
// initialize the state
//-------------------------------------------------
-void ymadpcm_b_channel::load_start()
+void adpcm_b_channel::load_start()
{
m_status = (m_status & ~STATUS_EOS) | STATUS_PLAYING;
m_curaddress = m_regs.external() ? (m_regs.start() << address_shift()) : 0;
@@ -663,43 +699,42 @@ void ymadpcm_b_channel::load_start()
//*********************************************************
//-------------------------------------------------
-// ymadpcm_b_engine - constructor
+// adpcm_b_engine - constructor
//-------------------------------------------------
-ymadpcm_b_engine::ymadpcm_b_engine(device_t &device, read8sm_delegate reader, write8sm_delegate writer, u32 addrshift)
+adpcm_b_engine::adpcm_b_engine(ymfm_interface &intf, uint32_t addrshift) :
+ m_intf(intf)
{
// create the channel (only one supported for now, but leaving possibilities open)
- m_channel[0] = std::make_unique<ymadpcm_b_channel>(*this, reader, writer, addrshift);
+ m_channel = std::make_unique<adpcm_b_channel>(*this, addrshift);
}
//-------------------------------------------------
-// save - register for save states
+// reset - reset the engine state
//-------------------------------------------------
-void ymadpcm_b_engine::save(device_t &device)
+void adpcm_b_engine::reset()
{
- // save our state
- m_regs.save(device);
+ // reset registers
+ m_regs.reset();
- // save channel state
- for (int chnum = 0; chnum < std::size(m_channel); chnum++)
- m_channel[chnum]->save(device, chnum);
+ // reset each channel
+ m_channel->reset();
}
//-------------------------------------------------
-// reset - reset the engine state
+// save_restore - save or restore the data
//-------------------------------------------------
-void ymadpcm_b_engine::reset()
+void adpcm_b_engine::save_restore(ymfm_saved_state &state)
{
- // reset registers
- m_regs.reset();
+ // save our state
+ m_regs.save_restore(state);
- // reset each channel
- for (auto &chan : m_channel)
- chan->reset();
+ // save channel state
+ m_channel->save_restore(state);
}
@@ -707,12 +742,10 @@ void ymadpcm_b_engine::reset()
// clock - master clocking function
//-------------------------------------------------
-void ymadpcm_b_engine::clock(u32 chanmask)
+void adpcm_b_engine::clock()
{
// clock each channel, setting a bit in result if it finished
- for (int chnum = 0; chnum < std::size(m_channel); chnum++)
- if (BIT(chanmask, chnum))
- m_channel[chnum]->clock();
+ m_channel->clock();
}
@@ -720,25 +753,29 @@ void ymadpcm_b_engine::clock(u32 chanmask)
// output - master output function
//-------------------------------------------------
-void ymadpcm_b_engine::output(s32 outputs[2], u32 rshift, u32 chanmask)
+template<int NumOutputs>
+void adpcm_b_engine::output(ymfm_output<NumOutputs> &output, uint32_t rshift)
{
// compute the output of each channel
- for (int chnum = 0; chnum < std::size(m_channel); chnum++)
- if (BIT(chanmask, chnum))
- m_channel[chnum]->output(outputs, rshift);
+ m_channel->output(output, rshift);
}
+template void adpcm_b_engine::output<1>(ymfm_output<1> &output, uint32_t rshift);
+template void adpcm_b_engine::output<2>(ymfm_output<2> &output, uint32_t rshift);
+
//-------------------------------------------------
// write - handle writes to the ADPCM-B registers
//-------------------------------------------------
-void ymadpcm_b_engine::write(u32 regnum, u8 data)
+void adpcm_b_engine::write(uint32_t regnum, uint8_t data)
{
// store the raw value to the register array;
// most writes are passive, consumed only when needed
m_regs.write(regnum, data);
// let the channel handle any special writes
- m_channel[0]->write(regnum, data);
+ m_channel->write(regnum, data);
+}
+
}
diff --git a/3rdparty/ymfm/src/ymfm_adpcm.h b/3rdparty/ymfm/src/ymfm_adpcm.h
new file mode 100644
index 00000000000..4b4af0fddd6
--- /dev/null
+++ b/3rdparty/ymfm/src/ymfm_adpcm.h
@@ -0,0 +1,411 @@
+// BSD 3-Clause License
+//
+// Copyright (c) 2021, Aaron Giles
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef YMFM_ADPCM_H
+#define YMFM_ADPCM_H
+
+#pragma once
+
+#include "ymfm.h"
+
+namespace ymfm
+{
+
+//*********************************************************
+// INTERFACE CLASSES
+//*********************************************************
+
+// forward declarations
+class adpcm_a_engine;
+class adpcm_b_engine;
+
+
+// ======================> adpcm_a_registers
+
+//
+// ADPCM-A register map:
+//
+// System-wide registers:
+// 00 x------- Dump (disable=1) or keyon (0) control
+// --xxxxxx Mask of channels to dump or keyon
+// 01 --xxxxxx Total level
+// 02 xxxxxxxx Test register
+// 08-0D x------- Pan left
+// -x------ Pan right
+// ---xxxxx Instrument level
+// 10-15 xxxxxxxx Start address (low)
+// 18-1D xxxxxxxx Start address (high)
+// 20-25 xxxxxxxx End address (low)
+// 28-2D xxxxxxxx End address (high)
+//
+class adpcm_a_registers
+{
+public:
+ // constants
+ static constexpr uint32_t OUTPUTS = 2;
+ static constexpr uint32_t CHANNELS = 6;
+ static constexpr uint32_t REGISTERS = 0x30;
+ static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1;
+
+ // constructor
+ adpcm_a_registers() { }
+
+ // reset to initial state
+ void reset();
+
+ // save/restore
+ void save_restore(ymfm_saved_state &state);
+
+ // map channel number to register offset
+ static constexpr uint32_t channel_offset(uint32_t chnum)
+ {
+ assert(chnum < CHANNELS);
+ return chnum;
+ }
+
+ // direct read/write access
+ void write(uint32_t index, uint8_t data) { m_regdata[index] = data; }
+
+ // system-wide registers
+ uint32_t dump() const { return bitfield(m_regdata[0x00], 7); }
+ uint32_t dump_mask() const { return bitfield(m_regdata[0x00], 0, 6); }
+ uint32_t total_level() const { return bitfield(m_regdata[0x01], 0, 6); }
+ uint32_t test() const { return m_regdata[0x02]; }
+
+ // per-channel registers
+ uint32_t ch_pan_left(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x08], 7); }
+ uint32_t ch_pan_right(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x08], 6); }
+ uint32_t ch_instrument_level(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x08], 0, 5); }
+ uint32_t ch_start(uint32_t choffs) const { return m_regdata[choffs + 0x10] | (m_regdata[choffs + 0x18] << 8); }
+ uint32_t ch_end(uint32_t choffs) const { return m_regdata[choffs + 0x20] | (m_regdata[choffs + 0x28] << 8); }
+
+ // per-channel writes
+ void write_start(uint32_t choffs, uint32_t address)
+ {
+ write(choffs + 0x10, address);
+ write(choffs + 0x18, address >> 8);
+ }
+ void write_end(uint32_t choffs, uint32_t address)
+ {
+ write(choffs + 0x20, address);
+ write(choffs + 0x28, address >> 8);
+ }
+
+private:
+ // internal state
+ uint8_t m_regdata[REGISTERS]; // register data
+};
+
+
+// ======================> adpcm_a_channel
+
+class adpcm_a_channel
+{
+public:
+ // constructor
+ adpcm_a_channel(adpcm_a_engine &owner, uint32_t choffs, uint32_t addrshift);
+
+ // reset the channel state
+ void reset();
+
+ // save/restore
+ void save_restore(ymfm_saved_state &state);
+
+ // signal key on/off
+ void keyonoff(bool on);
+
+ // master clockingfunction
+ bool clock();
+
+ // return the computed output value, with panning applied
+ template<int NumOutputs>
+ void output(ymfm_output<NumOutputs> &output) const;
+
+private:
+ // internal state
+ uint32_t const m_choffs; // channel offset
+ uint32_t const m_address_shift; // address bits shift-left
+ uint32_t m_playing; // currently playing?
+ uint32_t m_curnibble; // index of the current nibble
+ uint32_t m_curbyte; // current byte of data
+ uint32_t m_curaddress; // current address
+ int32_t m_accumulator; // accumulator
+ int32_t m_step_index; // index in the stepping table
+ adpcm_a_registers &m_regs; // reference to registers
+ adpcm_a_engine &m_owner; // reference to our owner
+};
+
+
+// ======================> adpcm_a_engine
+
+class adpcm_a_engine
+{
+public:
+ static constexpr int CHANNELS = adpcm_a_registers::CHANNELS;
+
+ // constructor
+ adpcm_a_engine(ymfm_interface &intf, uint32_t addrshift);
+
+ // reset our status
+ void reset();
+
+ // save/restore
+ void save_restore(ymfm_saved_state &state);
+
+ // master clocking function
+ uint32_t clock(uint32_t chanmask);
+
+ // compute sum of channel outputs
+ template<int NumOutputs>
+ void output(ymfm_output<NumOutputs> &output, uint32_t chanmask);
+
+ // write to the ADPCM-A registers
+ void write(uint32_t regnum, uint8_t data);
+
+ // set the start/end address for a channel (for hardcoded YM2608 percussion)
+ void set_start_end(uint8_t chnum, uint16_t start, uint16_t end)
+ {
+ uint32_t choffs = adpcm_a_registers::channel_offset(chnum);
+ m_regs.write_start(choffs, start);
+ m_regs.write_end(choffs, end);
+ }
+
+ // return a reference to our interface
+ ymfm_interface &intf() { return m_intf; }
+
+ // return a reference to our registers
+ adpcm_a_registers &regs() { return m_regs; }
+
+private:
+ // internal state
+ ymfm_interface &m_intf; // reference to the interface
+ std::unique_ptr<adpcm_a_channel> m_channel[CHANNELS]; // array of channels
+ adpcm_a_registers m_regs; // registers
+};
+
+
+// ======================> adpcm_b_registers
+
+//
+// ADPCM-B register map:
+//
+// System-wide registers:
+// 00 x------- Start of synthesis/analysis
+// -x------ Record
+// --x----- External/manual driving
+// ---x---- Repeat playback
+// ----x--- Speaker off
+// -------x Reset
+// 01 x------- Pan left
+// -x------ Pan right
+// ----x--- Start conversion
+// -----x-- DAC enable
+// ------x- DRAM access (1=8-bit granularity; 0=1-bit)
+// -------x RAM/ROM (1=ROM, 0=RAM)
+// 02 xxxxxxxx Start address (low)
+// 03 xxxxxxxx Start address (high)
+// 04 xxxxxxxx End address (low)
+// 05 xxxxxxxx End address (high)
+// 06 xxxxxxxx Prescale value (low)
+// 07 -----xxx Prescale value (high)
+// 08 xxxxxxxx CPU data/buffer
+// 09 xxxxxxxx Delta-N frequency scale (low)
+// 0a xxxxxxxx Delta-N frequency scale (high)
+// 0b xxxxxxxx Level control
+// 0c xxxxxxxx Limit address (low)
+// 0d xxxxxxxx Limit address (high)
+// 0e xxxxxxxx DAC data [YM2608/10]
+// 0f xxxxxxxx PCM data [YM2608/10]
+// 0e xxxxxxxx DAC data high [Y8950]
+// 0f xx------ DAC data low [Y8950]
+// 10 -----xxx DAC data exponent [Y8950]
+//
+class adpcm_b_registers
+{
+public:
+ // constants
+ static constexpr uint32_t REGISTERS = 0x11;
+
+ // constructor
+ adpcm_b_registers() { }
+
+ // reset to initial state
+ void reset();
+
+ // save/restore
+ void save_restore(ymfm_saved_state &state);
+
+ // direct read/write access
+ void write(uint32_t index, uint8_t data) { m_regdata[index] = data; }
+
+ // system-wide registers
+ uint32_t execute() const { return bitfield(m_regdata[0x00], 7); }
+ uint32_t record() const { return bitfield(m_regdata[0x00], 6); }
+ uint32_t external() const { return bitfield(m_regdata[0x00], 5); }
+ uint32_t repeat() const { return bitfield(m_regdata[0x00], 4); }
+ uint32_t speaker() const { return bitfield(m_regdata[0x00], 3); }
+ uint32_t resetflag() const { return bitfield(m_regdata[0x00], 0); }
+ uint32_t pan_left() const { return bitfield(m_regdata[0x01], 7); }
+ uint32_t pan_right() const { return bitfield(m_regdata[0x01], 6); }
+ uint32_t start_conversion() const { return bitfield(m_regdata[0x01], 3); }
+ uint32_t dac_enable() const { return bitfield(m_regdata[0x01], 2); }
+ uint32_t dram_8bit() const { return bitfield(m_regdata[0x01], 1); }
+ uint32_t rom_ram() const { return bitfield(m_regdata[0x01], 0); }
+ uint32_t start() const { return m_regdata[0x02] | (m_regdata[0x03] << 8); }
+ uint32_t end() const { return m_regdata[0x04] | (m_regdata[0x05] << 8); }
+ uint32_t prescale() const { return m_regdata[0x06] | (bitfield(m_regdata[0x07], 0, 3) << 8); }
+ uint32_t cpudata() const { return m_regdata[0x08]; }
+ uint32_t delta_n() const { return m_regdata[0x09] | (m_regdata[0x0a] << 8); }
+ uint32_t level() const { return m_regdata[0x0b]; }
+ uint32_t limit() const { return m_regdata[0x0c] | (m_regdata[0x0d] << 8); }
+ uint32_t dac() const { return m_regdata[0x0e]; }
+ uint32_t pcm() const { return m_regdata[0x0f]; }
+
+private:
+ // internal state
+ uint8_t m_regdata[REGISTERS]; // register data
+};
+
+
+// ======================> adpcm_b_channel
+
+class adpcm_b_channel
+{
+ static constexpr int32_t STEP_MIN = 127;
+ static constexpr int32_t STEP_MAX = 24576;
+
+public:
+ static constexpr uint8_t STATUS_EOS = 0x01;
+ static constexpr uint8_t STATUS_BRDY = 0x02;
+ static constexpr uint8_t STATUS_PLAYING = 0x04;
+
+ // constructor
+ adpcm_b_channel(adpcm_b_engine &owner, uint32_t addrshift);
+
+ // reset the channel state
+ void reset();
+
+ // save/restore
+ void save_restore(ymfm_saved_state &state);
+
+ // signal key on/off
+ void keyonoff(bool on);
+
+ // master clocking function
+ void clock();
+
+ // return the computed output value, with panning applied
+ template<int NumOutputs>
+ void output(ymfm_output<NumOutputs> &output, uint32_t rshift) const;
+
+ // return the status register
+ uint8_t status() const { return m_status; }
+
+ // handle special register reads
+ uint8_t read(uint32_t regnum);
+
+ // handle special register writes
+ void write(uint32_t regnum, uint8_t value);
+
+private:
+ // helper - return the current address shift
+ uint32_t address_shift() const;
+
+ // load the start address
+ void load_start();
+
+ // limit checker
+ bool at_limit() const { return (m_curaddress >> address_shift()) >= m_regs.limit(); }
+
+ // end checker
+ bool at_end() const { return (m_curaddress >> address_shift()) > m_regs.end(); }
+
+ // internal state
+ uint32_t const m_address_shift; // address bits shift-left
+ uint32_t m_status; // currently playing?
+ uint32_t m_curnibble; // index of the current nibble
+ uint32_t m_curbyte; // current byte of data
+ uint32_t m_dummy_read; // dummy read tracker
+ uint32_t m_position; // current fractional position
+ uint32_t m_curaddress; // current address
+ int32_t m_accumulator; // accumulator
+ int32_t m_prev_accum; // previous accumulator (for linear interp)
+ int32_t m_adpcm_step; // next forecast
+ adpcm_b_registers &m_regs; // reference to registers
+ adpcm_b_engine &m_owner; // reference to our owner
+};
+
+
+// ======================> adpcm_b_engine
+
+class adpcm_b_engine
+{
+public:
+ // constructor
+ adpcm_b_engine(ymfm_interface &intf, uint32_t addrshift = 0);
+
+ // reset our status
+ void reset();
+
+ // save/restore
+ void save_restore(ymfm_saved_state &state);
+
+ // master clocking function
+ void clock();
+
+ // compute sum of channel outputs
+ template<int NumOutputs>
+ void output(ymfm_output<NumOutputs> &output, uint32_t rshift);
+
+ // read from the ADPCM-B registers
+ uint32_t read(uint32_t regnum) { return m_channel->read(regnum); }
+
+ // write to the ADPCM-B registers
+ void write(uint32_t regnum, uint8_t data);
+
+ // status
+ uint8_t status() const { return m_channel->status(); }
+
+ // return a reference to our interface
+ ymfm_interface &intf() { return m_intf; }
+
+ // return a reference to our registers
+ adpcm_b_registers &regs() { return m_regs; }
+
+private:
+ // internal state
+ ymfm_interface &m_intf; // reference to our interface
+ std::unique_ptr<adpcm_b_channel> m_channel; // channel pointer
+ adpcm_b_registers m_regs; // registers
+};
+
+}
+
+#endif // YMFM_ADPCM_H
diff --git a/3rdparty/ymfm/src/ymfm_fm.h b/3rdparty/ymfm/src/ymfm_fm.h
new file mode 100644
index 00000000000..c4d4982b8e0
--- /dev/null
+++ b/3rdparty/ymfm/src/ymfm_fm.h
@@ -0,0 +1,449 @@
+// BSD 3-Clause License
+//
+// Copyright (c) 2021, Aaron Giles
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef YMFM_FM_H
+#define YMFM_FM_H
+
+#pragma once
+
+namespace ymfm
+{
+
+//*********************************************************
+// GLOBAL ENUMERATORS
+//*********************************************************
+
+// three different keyon sources; actual keyon is an OR over all of these
+enum keyon_type : uint32_t
+{
+ KEYON_NORMAL = 0,
+ KEYON_RHYTHM = 1,
+ KEYON_CSM = 2
+};
+
+
+
+//*********************************************************
+// CORE IMPLEMENTATION
+//*********************************************************
+
+// ======================> opdata_cache
+
+// this class holds data that is computed once at the start of clocking
+// and remains static during subsequent sound generation
+struct opdata_cache
+{
+ // set phase_step to this value to recalculate it each sample; needed
+ // in the case of PM LFO changes
+ static constexpr uint32_t PHASE_STEP_DYNAMIC = 1;
+
+ uint16_t const *waveform; // base of sine table
+ uint32_t phase_step; // phase step, or PHASE_STEP_DYNAMIC if PM is active
+ uint32_t total_level; // total level * 8 + KSL
+ uint32_t block_freq; // raw block frequency value (used to compute phase_step)
+ int32_t detune; // detuning value (used to compute phase_step)
+ uint32_t multiple; // multiple value (x.1, used to compute phase_step)
+ uint32_t eg_sustain; // sustain level, shifted up to envelope values
+ uint8_t eg_rate[EG_STATES]; // envelope rate, including KSR
+ uint8_t eg_shift = 0; // envelope shift amount
+};
+
+
+// ======================> fm_registers_base
+
+// base class for family-specific register classes; this provides a few
+// constants, common defaults, and helpers, but mostly each derived class is
+// responsible for defining all commonly-called methods
+class fm_registers_base
+{
+public:
+ // this value is returned from the write() function for rhythm channels
+ static constexpr uint32_t RHYTHM_CHANNEL = 0xff;
+
+ // this is the size of a full sin waveform
+ static constexpr uint32_t WAVEFORM_LENGTH = 0x400;
+
+ //
+ // the following constants need to be defined per family:
+ // uint32_t OUTPUTS: The number of outputs exposed (1-4)
+ // uint32_t CHANNELS: The number of channels on the chip
+ // uint32_t ALL_CHANNELS: A bitmask of all channels
+ // uint32_t OPERATORS: The number of operators on the chip
+ // uint32_t WAVEFORMS: The number of waveforms offered
+ // uint32_t REGISTERS: The number of 8-bit registers allocated
+ // uint32_t DEFAULT_PRESCALE: The starting clock prescale
+ // uint32_t EG_CLOCK_DIVIDER: The clock divider of the envelope generator
+ // uint32_t CSM_TRIGGER_MASK: Mask of channels to trigger in CSM mode
+ // uint32_t REG_MODE: The address of the "mode" register controlling timers
+ // uint8_t STATUS_TIMERA: Status bit to set when timer A fires
+ // uint8_t STATUS_TIMERB: Status bit to set when tiemr B fires
+ // uint8_t STATUS_BUSY: Status bit to set when the chip is busy
+ // uint8_t STATUS_IRQ: Status bit to set when an IRQ is signalled
+ //
+ // the following constants are uncommon:
+ // bool DYNAMIC_OPS: True if ops/channel can be changed at runtime (OPL3+)
+ // bool EG_HAS_DEPRESS: True if the chip has a DP ("depress"?) envelope stage (OPLL)
+ // bool EG_HAS_REVERB: True if the chip has a faux reverb envelope stage (OPQ/OPZ)
+ // bool EG_HAS_SSG: True if the chip has SSG envelope support (OPN)
+ // bool MODULATOR_DELAY: True if the modulator is delayed by 1 sample (OPL pre-OPL3)
+ //
+ static constexpr bool DYNAMIC_OPS = false;
+ static constexpr bool EG_HAS_DEPRESS = false;
+ static constexpr bool EG_HAS_REVERB = false;
+ static constexpr bool EG_HAS_SSG = false;
+ static constexpr bool MODULATOR_DELAY = false;
+
+ // system-wide register defaults
+ uint32_t status_mask() const { return 0; } // OPL only
+ uint32_t irq_reset() const { return 0; } // OPL only
+ uint32_t noise_enable() const { return 0; } // OPM only
+ uint32_t rhythm_enable() const { return 0; } // OPL only
+
+ // per-operator register defaults
+ uint32_t op_ssg_eg_enable(uint32_t opoffs) const { return 0; } // OPN(A) only
+ uint32_t op_ssg_eg_mode(uint32_t opoffs) const { return 0; } // OPN(A) only
+
+protected:
+ // helper to encode four operator numbers into a 32-bit value in the
+ // operator maps for each register class
+ static constexpr uint32_t operator_list(uint8_t o1 = 0xff, uint8_t o2 = 0xff, uint8_t o3 = 0xff, uint8_t o4 = 0xff)
+ {
+ return o1 | (o2 << 8) | (o3 << 16) | (o4 << 24);
+ }
+
+ // helper to apply KSR to the raw ADSR rate, ignoring ksr if the
+ // raw value is 0, and clamping to 63
+ static constexpr uint32_t effective_rate(uint32_t rawrate, uint32_t ksr)
+ {
+ return (rawrate == 0) ? 0 : std::min<uint32_t>(rawrate + ksr, 63);
+ }
+};
+
+
+
+//*********************************************************
+// CORE ENGINE CLASSES
+//*********************************************************
+
+// forward declarations
+template<class RegisterType> class fm_engine_base;
+
+// ======================> fm_operator
+
+// fm_operator represents an FM operator (or "slot" in FM parlance), which
+// produces an output sine wave modulated by an envelope
+template<class RegisterType>
+class fm_operator
+{
+ // "quiet" value, used to optimize when we can skip doing working
+ static constexpr uint32_t EG_QUIET = 0x200;
+
+public:
+ // constructor
+ fm_operator(fm_engine_base<RegisterType> &owner, uint32_t opoffs);
+
+ // save/restore
+ void save_restore(ymfm_saved_state &state);
+
+ // reset the operator state
+ void reset();
+
+ // return the operator/channel offset
+ uint32_t opoffs() const { return m_opoffs; }
+ uint32_t choffs() const { return m_choffs; }
+
+ // set the current channel
+ void set_choffs(uint32_t choffs) { m_choffs = choffs; }
+
+ // prepare prior to clocking
+ bool prepare();
+
+ // master clocking function
+ void clock(uint32_t env_counter, int32_t lfo_raw_pm);
+
+ // return the current phase value
+ uint32_t phase() const { return m_phase >> 10; }
+
+ // compute operator volume
+ int32_t compute_volume(uint32_t phase, uint32_t am_offset) const;
+
+ // compute volume for the OPM noise channel
+ int32_t compute_noise_volume(uint32_t am_offset) const;
+
+ // key state control
+ void keyonoff(uint32_t on, keyon_type type);
+
+ // return a reference to our registers
+ RegisterType &regs() const { return m_regs; }
+
+ // simple getters for debugging
+ envelope_state debug_eg_state() const { return m_env_state; }
+ uint16_t debug_eg_attenuation() const { return m_env_attenuation; }
+ opdata_cache &debug_cache() { return m_cache; }
+
+private:
+ // start the attack phase
+ void start_attack(bool is_restart = false);
+
+ // start the release phase
+ void start_release();
+
+ // clock phases
+ void clock_keystate(uint32_t keystate);
+ void clock_ssg_eg_state();
+ void clock_envelope(uint32_t env_counter);
+ void clock_phase(int32_t lfo_raw_pm);
+
+ // return effective attenuation of the envelope
+ uint32_t envelope_attenuation(uint32_t am_offset) const;
+
+ // internal state
+ uint32_t m_choffs; // channel offset in registers
+ uint32_t m_opoffs; // operator offset in registers
+ uint32_t m_phase; // current phase value (10.10 format)
+ uint16_t m_env_attenuation; // computed envelope attenuation (4.6 format)
+ envelope_state m_env_state; // current envelope state
+ uint8_t m_ssg_inverted; // non-zero if the output should be inverted (bit 0)
+ uint8_t m_key_state; // current key state: on or off (bit 0)
+ uint8_t m_keyon_live; // live key on state (bit 0 = direct, bit 1 = rhythm, bit 2 = CSM)
+ opdata_cache m_cache; // cached values for performance
+ RegisterType &m_regs; // direct reference to registers
+ fm_engine_base<RegisterType> &m_owner; // reference to the owning engine
+};
+
+
+// ======================> fm_channel
+
+// fm_channel represents an FM channel which combines the output of 2 or 4
+// operators into a final result
+template<class RegisterType>
+class fm_channel
+{
+ using output_data = ymfm_output<RegisterType::OUTPUTS>;
+
+public:
+ // constructor
+ fm_channel(fm_engine_base<RegisterType> &owner, uint32_t choffs);
+
+ // save/restore
+ void save_restore(ymfm_saved_state &state);
+
+ // reset the channel state
+ void reset();
+
+ // return the channel offset
+ uint32_t choffs() const { return m_choffs; }
+
+ // assign operators
+ void assign(uint32_t index, fm_operator<RegisterType> *op)
+ {
+ assert(index < array_size(m_op));
+ m_op[index] = op;
+ if (op != nullptr)
+ op->set_choffs(m_choffs);
+ }
+
+ // signal key on/off to our operators
+ void keyonoff(uint32_t states, keyon_type type, uint32_t chnum);
+
+ // prepare prior to clocking
+ bool prepare();
+
+ // master clocking function
+ void clock(uint32_t env_counter, int32_t lfo_raw_pm);
+
+ // specific 2-operator and 4-operator output handlers
+ void output_2op(output_data &output, uint32_t rshift, int32_t clipmax) const;
+ void output_4op(output_data &output, uint32_t rshift, int32_t clipmax) const;
+
+ // compute the special OPL rhythm channel outputs
+ void output_rhythm_ch6(output_data &output, uint32_t rshift, int32_t clipmax) const;
+ void output_rhythm_ch7(uint32_t phase_select, output_data &output, uint32_t rshift, int32_t clipmax) const;
+ void output_rhythm_ch8(uint32_t phase_select, output_data &output, uint32_t rshift, int32_t clipmax) const;
+
+ // are we a 4-operator channel or a 2-operator one?
+ bool is4op() const
+ {
+ if (RegisterType::DYNAMIC_OPS)
+ return (m_op[2] != nullptr);
+ return (RegisterType::OPERATORS / RegisterType::CHANNELS == 4);
+ }
+
+ // return a reference to our registers
+ RegisterType &regs() const { return m_regs; }
+
+ // simple getters for debugging
+ fm_operator<RegisterType> *debug_operator(uint32_t index) const { return m_op[index]; }
+
+private:
+ // helper to add values to the outputs based on channel enables
+ void add_to_output(uint32_t choffs, output_data &output, int32_t value) const
+ {
+ // create these constants to appease overzealous compilers checking array
+ // bounds in unreachable code (looking at you, clang)
+ constexpr int out0_index = 0;
+ constexpr int out1_index = 1 % RegisterType::OUTPUTS;
+ constexpr int out2_index = 2 % RegisterType::OUTPUTS;
+ constexpr int out3_index = 3 % RegisterType::OUTPUTS;
+
+ if (RegisterType::OUTPUTS == 1 || m_regs.ch_output_0(choffs))
+ output.data[out0_index] += value;
+ if (RegisterType::OUTPUTS >= 2 && m_regs.ch_output_1(choffs))
+ output.data[out1_index] += value;
+ if (RegisterType::OUTPUTS >= 3 && m_regs.ch_output_2(choffs))
+ output.data[out2_index] += value;
+ if (RegisterType::OUTPUTS >= 4 && m_regs.ch_output_3(choffs))
+ output.data[out3_index] += value;
+ }
+
+ // internal state
+ uint32_t m_choffs; // channel offset in registers
+ int16_t m_feedback[2]; // feedback memory for operator 1
+ mutable int16_t m_feedback_in; // next input value for op 1 feedback (set in output)
+ fm_operator<RegisterType> *m_op[4]; // up to 4 operators
+ RegisterType &m_regs; // direct reference to registers
+ fm_engine_base<RegisterType> &m_owner; // reference to the owning engine
+};
+
+
+// ======================> fm_engine_base
+
+// fm_engine_base represents a set of operators and channels which together
+// form a Yamaha FM core; chips that implement other engines (ADPCM, wavetable,
+// etc) take this output and combine it with the others externally
+template<class RegisterType>
+class fm_engine_base : public ymfm_engine_callbacks
+{
+public:
+ // expose some constants from the registers
+ static constexpr uint32_t OUTPUTS = RegisterType::OUTPUTS;
+ static constexpr uint32_t CHANNELS = RegisterType::CHANNELS;
+ static constexpr uint32_t ALL_CHANNELS = RegisterType::ALL_CHANNELS;
+ static constexpr uint32_t OPERATORS = RegisterType::OPERATORS;
+
+ // also expose status flags for consumers that inject additional bits
+ static constexpr uint8_t STATUS_TIMERA = RegisterType::STATUS_TIMERA;
+ static constexpr uint8_t STATUS_TIMERB = RegisterType::STATUS_TIMERB;
+ static constexpr uint8_t STATUS_BUSY = RegisterType::STATUS_BUSY;
+ static constexpr uint8_t STATUS_IRQ = RegisterType::STATUS_IRQ;
+
+ // expose the correct output class
+ using output_data = ymfm_output<OUTPUTS>;
+
+ // constructor
+ fm_engine_base(ymfm_interface &intf);
+
+ // save/restore
+ void save_restore(ymfm_saved_state &state);
+
+ // reset the overall state
+ void reset();
+
+ // master clocking function
+ uint32_t clock(uint32_t chanmask);
+
+ // compute sum of channel outputs
+ void output(output_data &output, uint32_t rshift, int32_t clipmax, uint32_t chanmask) const;
+
+ // write to the OPN registers
+ void write(uint16_t regnum, uint8_t data);
+
+ // return the current status
+ uint8_t status() const;
+
+ // set/reset bits in the status register, updating the IRQ status
+ uint8_t set_reset_status(uint8_t set, uint8_t reset)
+ {
+ m_status = (m_status | set) & ~(reset | STATUS_BUSY);
+ m_intf.ymfm_sync_check_interrupts();
+ return m_status;
+ }
+
+ // set the IRQ mask
+ void set_irq_mask(uint8_t mask) { m_irq_mask = mask; m_intf.ymfm_sync_check_interrupts(); }
+
+ // return the current clock prescale
+ uint32_t clock_prescale() const { return m_clock_prescale; }
+
+ // set prescale factor (2/3/6)
+ void set_clock_prescale(uint32_t prescale) { m_clock_prescale = prescale; }
+
+ // compute sample rate
+ uint32_t sample_rate(uint32_t baseclock) const { return baseclock / (m_clock_prescale * OPERATORS); }
+
+ // return the owning device
+ ymfm_interface &intf() const { return m_intf; }
+
+ // return a reference to our registers
+ RegisterType &regs() { return m_regs; }
+
+ // invalidate any caches
+ void invalidate_caches() { m_modified_channels = RegisterType::ALL_CHANNELS; }
+
+ // simple getters for debugging
+ fm_channel<RegisterType> *debug_channel(uint32_t index) const { return m_channel[index].get(); }
+ fm_operator<RegisterType> *debug_operator(uint32_t index) const { return m_operator[index].get(); }
+
+public:
+ // timer callback; called by the interface when a timer fires
+ virtual void engine_timer_expired(uint32_t tnum) override;
+
+ // check interrupts; called by the interface after synchronization
+ virtual void engine_check_interrupts() override;
+
+ // mode register write; called by the interface after synchronization
+ virtual void engine_mode_write(uint8_t data) override;
+
+protected:
+ // assign the current set of operators to channels
+ void assign_operators();
+
+ // update the state of the given timer
+ void update_timer(uint32_t which, uint32_t enable);
+
+ // internal state
+ ymfm_interface &m_intf; // reference to the system interface
+ uint32_t m_env_counter; // envelope counter; low 2 bits are sub-counter
+ uint8_t m_status; // current status register
+ uint8_t m_clock_prescale; // prescale factor (2/3/6)
+ uint8_t m_irq_mask; // mask of which bits signal IRQs
+ uint8_t m_irq_state; // current IRQ state
+ uint8_t m_timer_running[2]; // current timer running state
+ uint32_t m_active_channels; // mask of active channels (computed by prepare)
+ uint32_t m_modified_channels; // mask of channels that have been modified
+ uint32_t m_prepare_count; // counter to do periodic prepare sweeps
+ RegisterType m_regs; // register accessor
+ std::unique_ptr<fm_channel<RegisterType>> m_channel[CHANNELS]; // channel pointers
+ std::unique_ptr<fm_operator<RegisterType>> m_operator[OPERATORS]; // operator pointers
+};
+
+}
+
+#endif // YMFM_FM_H
diff --git a/3rdparty/ymfm/src/ymfm_fm.ipp b/3rdparty/ymfm/src/ymfm_fm.ipp
new file mode 100644
index 00000000000..2e04330a40e
--- /dev/null
+++ b/3rdparty/ymfm/src/ymfm_fm.ipp
@@ -0,0 +1,1539 @@
+// BSD 3-Clause License
+//
+// Copyright (c) 2021, Aaron Giles
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+namespace ymfm
+{
+
+//*********************************************************
+// GLOBAL TABLE LOOKUPS
+//*********************************************************
+
+//-------------------------------------------------
+// abs_sin_attenuation - given a sin (phase) input
+// where the range 0-2*PI is mapped onto 10 bits,
+// return the absolute value of sin(input),
+// logarithmically-adjusted and treated as an
+// attenuation value, in 4.8 fixed point format
+//-------------------------------------------------
+
+inline uint32_t abs_sin_attenuation(uint32_t input)
+{
+ // the values here are stored as 4.8 logarithmic values for 1/4 phase
+ // this matches the internal format of the OPN chip, extracted from the die
+ static uint16_t const s_sin_table[256] =
+ {
+ 0x859,0x6c3,0x607,0x58b,0x52e,0x4e4,0x4a6,0x471,0x443,0x41a,0x3f5,0x3d3,0x3b5,0x398,0x37e,0x365,
+ 0x34e,0x339,0x324,0x311,0x2ff,0x2ed,0x2dc,0x2cd,0x2bd,0x2af,0x2a0,0x293,0x286,0x279,0x26d,0x261,
+ 0x256,0x24b,0x240,0x236,0x22c,0x222,0x218,0x20f,0x206,0x1fd,0x1f5,0x1ec,0x1e4,0x1dc,0x1d4,0x1cd,
+ 0x1c5,0x1be,0x1b7,0x1b0,0x1a9,0x1a2,0x19b,0x195,0x18f,0x188,0x182,0x17c,0x177,0x171,0x16b,0x166,
+ 0x160,0x15b,0x155,0x150,0x14b,0x146,0x141,0x13c,0x137,0x133,0x12e,0x129,0x125,0x121,0x11c,0x118,
+ 0x114,0x10f,0x10b,0x107,0x103,0x0ff,0x0fb,0x0f8,0x0f4,0x0f0,0x0ec,0x0e9,0x0e5,0x0e2,0x0de,0x0db,
+ 0x0d7,0x0d4,0x0d1,0x0cd,0x0ca,0x0c7,0x0c4,0x0c1,0x0be,0x0bb,0x0b8,0x0b5,0x0b2,0x0af,0x0ac,0x0a9,
+ 0x0a7,0x0a4,0x0a1,0x09f,0x09c,0x099,0x097,0x094,0x092,0x08f,0x08d,0x08a,0x088,0x086,0x083,0x081,
+ 0x07f,0x07d,0x07a,0x078,0x076,0x074,0x072,0x070,0x06e,0x06c,0x06a,0x068,0x066,0x064,0x062,0x060,
+ 0x05e,0x05c,0x05b,0x059,0x057,0x055,0x053,0x052,0x050,0x04e,0x04d,0x04b,0x04a,0x048,0x046,0x045,
+ 0x043,0x042,0x040,0x03f,0x03e,0x03c,0x03b,0x039,0x038,0x037,0x035,0x034,0x033,0x031,0x030,0x02f,
+ 0x02e,0x02d,0x02b,0x02a,0x029,0x028,0x027,0x026,0x025,0x024,0x023,0x022,0x021,0x020,0x01f,0x01e,
+ 0x01d,0x01c,0x01b,0x01a,0x019,0x018,0x017,0x017,0x016,0x015,0x014,0x014,0x013,0x012,0x011,0x011,
+ 0x010,0x00f,0x00f,0x00e,0x00d,0x00d,0x00c,0x00c,0x00b,0x00a,0x00a,0x009,0x009,0x008,0x008,0x007,
+ 0x007,0x007,0x006,0x006,0x005,0x005,0x005,0x004,0x004,0x004,0x003,0x003,0x003,0x002,0x002,0x002,
+ 0x002,0x001,0x001,0x001,0x001,0x001,0x001,0x001,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000
+ };
+
+ // if the top bit is set, we're in the second half of the curve
+ // which is a mirror image, so invert the index
+ if (bitfield(input, 8))
+ input = ~input;
+
+ // return the value from the table
+ return s_sin_table[input & 0xff];
+}
+
+
+//-------------------------------------------------
+// attenuation_to_volume - given a 5.8 fixed point
+// logarithmic attenuation value, return a 13-bit
+// linear volume
+//-------------------------------------------------
+
+inline uint32_t attenuation_to_volume(uint32_t input)
+{
+ // the values here are 10-bit mantissas with an implied leading bit
+ // this matches the internal format of the OPN chip, extracted from the die
+
+ // as a nod to performance, the implicit 0x400 bit is pre-incorporated, and
+ // the values are left-shifted by 2 so that a simple right shift is all that
+ // is needed; also the order is reversed to save a NOT on the input
+#define X(a) ((a | 0x400) << 2)
+ static uint16_t const s_power_table[256] =
+ {
+ X(0x3fa),X(0x3f5),X(0x3ef),X(0x3ea),X(0x3e4),X(0x3df),X(0x3da),X(0x3d4),
+ X(0x3cf),X(0x3c9),X(0x3c4),X(0x3bf),X(0x3b9),X(0x3b4),X(0x3ae),X(0x3a9),
+ X(0x3a4),X(0x39f),X(0x399),X(0x394),X(0x38f),X(0x38a),X(0x384),X(0x37f),
+ X(0x37a),X(0x375),X(0x370),X(0x36a),X(0x365),X(0x360),X(0x35b),X(0x356),
+ X(0x351),X(0x34c),X(0x347),X(0x342),X(0x33d),X(0x338),X(0x333),X(0x32e),
+ X(0x329),X(0x324),X(0x31f),X(0x31a),X(0x315),X(0x310),X(0x30b),X(0x306),
+ X(0x302),X(0x2fd),X(0x2f8),X(0x2f3),X(0x2ee),X(0x2e9),X(0x2e5),X(0x2e0),
+ X(0x2db),X(0x2d6),X(0x2d2),X(0x2cd),X(0x2c8),X(0x2c4),X(0x2bf),X(0x2ba),
+ X(0x2b5),X(0x2b1),X(0x2ac),X(0x2a8),X(0x2a3),X(0x29e),X(0x29a),X(0x295),
+ X(0x291),X(0x28c),X(0x288),X(0x283),X(0x27f),X(0x27a),X(0x276),X(0x271),
+ X(0x26d),X(0x268),X(0x264),X(0x25f),X(0x25b),X(0x257),X(0x252),X(0x24e),
+ X(0x249),X(0x245),X(0x241),X(0x23c),X(0x238),X(0x234),X(0x230),X(0x22b),
+ X(0x227),X(0x223),X(0x21e),X(0x21a),X(0x216),X(0x212),X(0x20e),X(0x209),
+ X(0x205),X(0x201),X(0x1fd),X(0x1f9),X(0x1f5),X(0x1f0),X(0x1ec),X(0x1e8),
+ X(0x1e4),X(0x1e0),X(0x1dc),X(0x1d8),X(0x1d4),X(0x1d0),X(0x1cc),X(0x1c8),
+ X(0x1c4),X(0x1c0),X(0x1bc),X(0x1b8),X(0x1b4),X(0x1b0),X(0x1ac),X(0x1a8),
+ X(0x1a4),X(0x1a0),X(0x19c),X(0x199),X(0x195),X(0x191),X(0x18d),X(0x189),
+ X(0x185),X(0x181),X(0x17e),X(0x17a),X(0x176),X(0x172),X(0x16f),X(0x16b),
+ X(0x167),X(0x163),X(0x160),X(0x15c),X(0x158),X(0x154),X(0x151),X(0x14d),
+ X(0x149),X(0x146),X(0x142),X(0x13e),X(0x13b),X(0x137),X(0x134),X(0x130),
+ X(0x12c),X(0x129),X(0x125),X(0x122),X(0x11e),X(0x11b),X(0x117),X(0x114),
+ X(0x110),X(0x10c),X(0x109),X(0x106),X(0x102),X(0x0ff),X(0x0fb),X(0x0f8),
+ X(0x0f4),X(0x0f1),X(0x0ed),X(0x0ea),X(0x0e7),X(0x0e3),X(0x0e0),X(0x0dc),
+ X(0x0d9),X(0x0d6),X(0x0d2),X(0x0cf),X(0x0cc),X(0x0c8),X(0x0c5),X(0x0c2),
+ X(0x0be),X(0x0bb),X(0x0b8),X(0x0b5),X(0x0b1),X(0x0ae),X(0x0ab),X(0x0a8),
+ X(0x0a4),X(0x0a1),X(0x09e),X(0x09b),X(0x098),X(0x094),X(0x091),X(0x08e),
+ X(0x08b),X(0x088),X(0x085),X(0x082),X(0x07e),X(0x07b),X(0x078),X(0x075),
+ X(0x072),X(0x06f),X(0x06c),X(0x069),X(0x066),X(0x063),X(0x060),X(0x05d),
+ X(0x05a),X(0x057),X(0x054),X(0x051),X(0x04e),X(0x04b),X(0x048),X(0x045),
+ X(0x042),X(0x03f),X(0x03c),X(0x039),X(0x036),X(0x033),X(0x030),X(0x02d),
+ X(0x02a),X(0x028),X(0x025),X(0x022),X(0x01f),X(0x01c),X(0x019),X(0x016),
+ X(0x014),X(0x011),X(0x00e),X(0x00b),X(0x008),X(0x006),X(0x003),X(0x000)
+ };
+#undef X
+
+ // look up the fractional part, then shift by the whole
+ return s_power_table[input & 0xff] >> (input >> 8);
+}
+
+
+//-------------------------------------------------
+// attenuation_increment - given a 6-bit ADSR
+// rate value and a 3-bit stepping index,
+// return a 4-bit increment to the attenutaion
+// for this step (or for the attack case, the
+// fractional scale factor to decrease by)
+//-------------------------------------------------
+
+inline uint32_t attenuation_increment(uint32_t rate, uint32_t index)
+{
+ static uint32_t const s_increment_table[64] =
+ {
+ 0x00000000, 0x00000000, 0x10101010, 0x10101010, // 0-3 (0x00-0x03)
+ 0x10101010, 0x10101010, 0x11101110, 0x11101110, // 4-7 (0x04-0x07)
+ 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 8-11 (0x08-0x0B)
+ 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 12-15 (0x0C-0x0F)
+ 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 16-19 (0x10-0x13)
+ 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 20-23 (0x14-0x17)
+ 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 24-27 (0x18-0x1B)
+ 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 28-31 (0x1C-0x1F)
+ 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 32-35 (0x20-0x23)
+ 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 36-39 (0x24-0x27)
+ 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 40-43 (0x28-0x2B)
+ 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 44-47 (0x2C-0x2F)
+ 0x11111111, 0x21112111, 0x21212121, 0x22212221, // 48-51 (0x30-0x33)
+ 0x22222222, 0x42224222, 0x42424242, 0x44424442, // 52-55 (0x34-0x37)
+ 0x44444444, 0x84448444, 0x84848484, 0x88848884, // 56-59 (0x38-0x3B)
+ 0x88888888, 0x88888888, 0x88888888, 0x88888888 // 60-63 (0x3C-0x3F)
+ };
+ return bitfield(s_increment_table[rate], 4*index, 4);
+}
+
+
+//-------------------------------------------------
+// detune_adjustment - given a 5-bit key code
+// value and a 3-bit detune parameter, return a
+// 6-bit signed phase displacement; this table
+// has been verified against Nuked's equations,
+// but the equations are rather complicated, so
+// we'll keep the simplicity of the table
+//-------------------------------------------------
+
+inline int32_t detune_adjustment(uint32_t detune, uint32_t keycode)
+{
+ static uint8_t const s_detune_adjustment[32][4] =
+ {
+ { 0, 0, 1, 2 }, { 0, 0, 1, 2 }, { 0, 0, 1, 2 }, { 0, 0, 1, 2 },
+ { 0, 1, 2, 2 }, { 0, 1, 2, 3 }, { 0, 1, 2, 3 }, { 0, 1, 2, 3 },
+ { 0, 1, 2, 4 }, { 0, 1, 3, 4 }, { 0, 1, 3, 4 }, { 0, 1, 3, 5 },
+ { 0, 2, 4, 5 }, { 0, 2, 4, 6 }, { 0, 2, 4, 6 }, { 0, 2, 5, 7 },
+ { 0, 2, 5, 8 }, { 0, 3, 6, 8 }, { 0, 3, 6, 9 }, { 0, 3, 7, 10 },
+ { 0, 4, 8, 11 }, { 0, 4, 8, 12 }, { 0, 4, 9, 13 }, { 0, 5, 10, 14 },
+ { 0, 5, 11, 16 }, { 0, 6, 12, 17 }, { 0, 6, 13, 19 }, { 0, 7, 14, 20 },
+ { 0, 8, 16, 22 }, { 0, 8, 16, 22 }, { 0, 8, 16, 22 }, { 0, 8, 16, 22 }
+ };
+ int32_t result = s_detune_adjustment[keycode][detune & 3];
+ return bitfield(detune, 2) ? -result : result;
+}
+
+
+//-------------------------------------------------
+// opm_key_code_to_phase_step - converts an
+// OPM concatenated block (3 bits), keycode
+// (4 bits) and key fraction (6 bits) to a 0.10
+// phase step, after applying the given delta;
+// this applies to OPM and OPZ, so it lives here
+// in a central location
+//-------------------------------------------------
+
+inline uint32_t opm_key_code_to_phase_step(uint32_t block_freq, int32_t delta)
+{
+ // The phase step is essentially the fnum in OPN-speak. To compute this table,
+ // we used the standard formula for computing the frequency of a note, and
+ // then converted that frequency to fnum using the formula documented in the
+ // YM2608 manual.
+ //
+ // However, the YM2608 manual describes everything in terms of a nominal 8MHz
+ // clock, which produces an FM clock of:
+ //
+ // 8000000 / 24(operators) / 6(prescale) = 55555Hz FM clock
+ //
+ // Whereas the descriptions for the YM2151 use a nominal 3.579545MHz clock:
+ //
+ // 3579545 / 32(operators) / 2(prescale) = 55930Hz FM clock
+ //
+ // To correct for this, the YM2608 formula was adjusted to use a clock of
+ // 8053920Hz, giving this equation for the fnum:
+ //
+ // fnum = (double(144) * freq * (1 << 20)) / double(8053920) / 4;
+ //
+ // Unfortunately, the computed table differs in a few spots from the data
+ // verified from an actual chip. The table below comes from David Viens'
+ // analysis, used with his permission.
+ static const uint32_t s_phase_step[12*64] =
+ {
+ 41568,41600,41632,41664,41696,41728,41760,41792,41856,41888,41920,41952,42016,42048,42080,42112,
+ 42176,42208,42240,42272,42304,42336,42368,42400,42464,42496,42528,42560,42624,42656,42688,42720,
+ 42784,42816,42848,42880,42912,42944,42976,43008,43072,43104,43136,43168,43232,43264,43296,43328,
+ 43392,43424,43456,43488,43552,43584,43616,43648,43712,43744,43776,43808,43872,43904,43936,43968,
+ 44032,44064,44096,44128,44192,44224,44256,44288,44352,44384,44416,44448,44512,44544,44576,44608,
+ 44672,44704,44736,44768,44832,44864,44896,44928,44992,45024,45056,45088,45152,45184,45216,45248,
+ 45312,45344,45376,45408,45472,45504,45536,45568,45632,45664,45728,45760,45792,45824,45888,45920,
+ 45984,46016,46048,46080,46144,46176,46208,46240,46304,46336,46368,46400,46464,46496,46528,46560,
+ 46656,46688,46720,46752,46816,46848,46880,46912,46976,47008,47072,47104,47136,47168,47232,47264,
+ 47328,47360,47392,47424,47488,47520,47552,47584,47648,47680,47744,47776,47808,47840,47904,47936,
+ 48032,48064,48096,48128,48192,48224,48288,48320,48384,48416,48448,48480,48544,48576,48640,48672,
+ 48736,48768,48800,48832,48896,48928,48992,49024,49088,49120,49152,49184,49248,49280,49344,49376,
+ 49440,49472,49504,49536,49600,49632,49696,49728,49792,49824,49856,49888,49952,49984,50048,50080,
+ 50144,50176,50208,50240,50304,50336,50400,50432,50496,50528,50560,50592,50656,50688,50752,50784,
+ 50880,50912,50944,50976,51040,51072,51136,51168,51232,51264,51328,51360,51424,51456,51488,51520,
+ 51616,51648,51680,51712,51776,51808,51872,51904,51968,52000,52064,52096,52160,52192,52224,52256,
+ 52384,52416,52448,52480,52544,52576,52640,52672,52736,52768,52832,52864,52928,52960,52992,53024,
+ 53120,53152,53216,53248,53312,53344,53408,53440,53504,53536,53600,53632,53696,53728,53792,53824,
+ 53920,53952,54016,54048,54112,54144,54208,54240,54304,54336,54400,54432,54496,54528,54592,54624,
+ 54688,54720,54784,54816,54880,54912,54976,55008,55072,55104,55168,55200,55264,55296,55360,55392,
+ 55488,55520,55584,55616,55680,55712,55776,55808,55872,55936,55968,56032,56064,56128,56160,56224,
+ 56288,56320,56384,56416,56480,56512,56576,56608,56672,56736,56768,56832,56864,56928,56960,57024,
+ 57120,57152,57216,57248,57312,57376,57408,57472,57536,57568,57632,57664,57728,57792,57824,57888,
+ 57952,57984,58048,58080,58144,58208,58240,58304,58368,58400,58464,58496,58560,58624,58656,58720,
+ 58784,58816,58880,58912,58976,59040,59072,59136,59200,59232,59296,59328,59392,59456,59488,59552,
+ 59648,59680,59744,59776,59840,59904,59936,60000,60064,60128,60160,60224,60288,60320,60384,60416,
+ 60512,60544,60608,60640,60704,60768,60800,60864,60928,60992,61024,61088,61152,61184,61248,61280,
+ 61376,61408,61472,61536,61600,61632,61696,61760,61824,61856,61920,61984,62048,62080,62144,62208,
+ 62272,62304,62368,62432,62496,62528,62592,62656,62720,62752,62816,62880,62944,62976,63040,63104,
+ 63200,63232,63296,63360,63424,63456,63520,63584,63648,63680,63744,63808,63872,63904,63968,64032,
+ 64096,64128,64192,64256,64320,64352,64416,64480,64544,64608,64672,64704,64768,64832,64896,64928,
+ 65024,65056,65120,65184,65248,65312,65376,65408,65504,65536,65600,65664,65728,65792,65856,65888,
+ 65984,66016,66080,66144,66208,66272,66336,66368,66464,66496,66560,66624,66688,66752,66816,66848,
+ 66944,66976,67040,67104,67168,67232,67296,67328,67424,67456,67520,67584,67648,67712,67776,67808,
+ 67904,67936,68000,68064,68128,68192,68256,68288,68384,68448,68512,68544,68640,68672,68736,68800,
+ 68896,68928,68992,69056,69120,69184,69248,69280,69376,69440,69504,69536,69632,69664,69728,69792,
+ 69920,69952,70016,70080,70144,70208,70272,70304,70400,70464,70528,70560,70656,70688,70752,70816,
+ 70912,70976,71040,71104,71136,71232,71264,71360,71424,71488,71552,71616,71648,71744,71776,71872,
+ 71968,72032,72096,72160,72192,72288,72320,72416,72480,72544,72608,72672,72704,72800,72832,72928,
+ 72992,73056,73120,73184,73216,73312,73344,73440,73504,73568,73632,73696,73728,73824,73856,73952,
+ 74080,74144,74208,74272,74304,74400,74432,74528,74592,74656,74720,74784,74816,74912,74944,75040,
+ 75136,75200,75264,75328,75360,75456,75488,75584,75648,75712,75776,75840,75872,75968,76000,76096,
+ 76224,76288,76352,76416,76448,76544,76576,76672,76736,76800,76864,76928,77024,77120,77152,77248,
+ 77344,77408,77472,77536,77568,77664,77696,77792,77856,77920,77984,78048,78144,78240,78272,78368,
+ 78464,78528,78592,78656,78688,78784,78816,78912,78976,79040,79104,79168,79264,79360,79392,79488,
+ 79616,79680,79744,79808,79840,79936,79968,80064,80128,80192,80256,80320,80416,80512,80544,80640,
+ 80768,80832,80896,80960,80992,81088,81120,81216,81280,81344,81408,81472,81568,81664,81696,81792,
+ 81952,82016,82080,82144,82176,82272,82304,82400,82464,82528,82592,82656,82752,82848,82880,82976
+ };
+
+ // extract the block (octave) first
+ uint32_t block = bitfield(block_freq, 10, 3);
+
+ // the keycode (bits 6-9) is "gappy", mapping 12 values over 16 in each
+ // octave; to correct for this, we multiply the 4-bit value by 3/4 (or
+ // rather subtract 1/4); note that a (invalid) value of 15 will bleed into
+ // the next octave -- this is confirmed
+ uint32_t adjusted_code = bitfield(block_freq, 6, 4) - bitfield(block_freq, 8, 2);
+
+ // now re-insert the 6-bit fraction
+ int32_t eff_freq = (adjusted_code << 6) | bitfield(block_freq, 0, 6);
+
+ // now that the gaps are removed, add the delta
+ eff_freq += delta;
+
+ // handle over/underflow by adjusting the block:
+ if (uint32_t(eff_freq) >= 768)
+ {
+ // minimum delta is -512 (PM), so we can only underflow by 1 octave
+ if (eff_freq < 0)
+ {
+ eff_freq += 768;
+ if (block-- == 0)
+ return s_phase_step[0] >> 7;
+ }
+
+ // maximum delta is +512+608 (PM+detune), so we can overflow by up to 2 octaves
+ else
+ {
+ eff_freq -= 768;
+ if (eff_freq >= 768)
+ block++, eff_freq -= 768;
+ if (block++ >= 7)
+ return s_phase_step[767];
+ }
+ }
+
+ // look up the phase shift for the key code, then shift by octave
+ return s_phase_step[eff_freq] >> (block ^ 7);
+}
+
+
+//-------------------------------------------------
+// opn_lfo_pm_phase_adjustment - given the 7 most
+// significant frequency number bits, plus a 3-bit
+// PM depth value and a signed 5-bit raw PM value,
+// return a signed PM adjustment to the frequency;
+// algorithm written to match Nuked behavior
+//-------------------------------------------------
+
+inline int32_t opn_lfo_pm_phase_adjustment(uint32_t fnum_bits, uint32_t pm_sensitivity, int32_t lfo_raw_pm)
+{
+ // this table encodes 2 shift values to apply to the top 7 bits
+ // of fnum; it is effectively a cheap multiply by a constant
+ // value containing 0-2 bits
+ static uint8_t const s_lfo_pm_shifts[8][8] =
+ {
+ { 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77 },
+ { 0x77, 0x77, 0x77, 0x77, 0x72, 0x72, 0x72, 0x72 },
+ { 0x77, 0x77, 0x77, 0x72, 0x72, 0x72, 0x17, 0x17 },
+ { 0x77, 0x77, 0x72, 0x72, 0x17, 0x17, 0x12, 0x12 },
+ { 0x77, 0x77, 0x72, 0x17, 0x17, 0x17, 0x12, 0x07 },
+ { 0x77, 0x77, 0x17, 0x12, 0x07, 0x07, 0x02, 0x01 },
+ { 0x77, 0x77, 0x17, 0x12, 0x07, 0x07, 0x02, 0x01 },
+ { 0x77, 0x77, 0x17, 0x12, 0x07, 0x07, 0x02, 0x01 }
+ };
+
+ // look up the relevant shifts
+ int32_t abs_pm = (lfo_raw_pm < 0) ? -lfo_raw_pm : lfo_raw_pm;
+ uint32_t const shifts = s_lfo_pm_shifts[pm_sensitivity][bitfield(abs_pm, 0, 3)];
+
+ // compute the adjustment
+ int32_t adjust = (fnum_bits >> bitfield(shifts, 0, 4)) + (fnum_bits >> bitfield(shifts, 4, 4));
+ if (pm_sensitivity > 5)
+ adjust <<= pm_sensitivity - 5;
+ adjust >>= 2;
+
+ // every 16 cycles it inverts sign
+ return (lfo_raw_pm < 0) ? -adjust : adjust;
+}
+
+
+
+//*********************************************************
+// FM OPERATOR
+//*********************************************************
+
+//-------------------------------------------------
+// fm_operator - constructor
+//-------------------------------------------------
+
+template<class RegisterType>
+fm_operator<RegisterType>::fm_operator(fm_engine_base<RegisterType> &owner, uint32_t opoffs) :
+ m_choffs(0),
+ m_opoffs(opoffs),
+ m_phase(0),
+ m_env_attenuation(0x3ff),
+ m_env_state(EG_RELEASE),
+ m_ssg_inverted(false),
+ m_key_state(0),
+ m_keyon_live(0),
+ m_regs(owner.regs()),
+ m_owner(owner)
+{
+}
+
+
+//-------------------------------------------------
+// reset - reset the channel state
+//-------------------------------------------------
+
+template<class RegisterType>
+void fm_operator<RegisterType>::reset()
+{
+ // reset our data
+ m_phase = 0;
+ m_env_attenuation = 0x3ff;
+ m_env_state = EG_RELEASE;
+ m_ssg_inverted = 0;
+ m_key_state = 0;
+ m_keyon_live = 0;
+}
+
+
+//-------------------------------------------------
+// save_restore - save or restore the data
+//-------------------------------------------------
+
+template<class RegisterType>
+void fm_operator<RegisterType>::save_restore(ymfm_saved_state &state)
+{
+ state.save_restore(m_phase);
+ state.save_restore(m_env_attenuation);
+ state.save_restore(m_env_state);
+ state.save_restore(m_ssg_inverted);
+ state.save_restore(m_key_state);
+ state.save_restore(m_keyon_live);
+}
+
+
+//-------------------------------------------------
+// prepare - prepare for clocking
+//-------------------------------------------------
+
+template<class RegisterType>
+bool fm_operator<RegisterType>::prepare()
+{
+ // cache the data
+ m_regs.cache_operator_data(m_choffs, m_opoffs, m_cache);
+
+ // clock the key state
+ clock_keystate(uint32_t(m_keyon_live != 0));
+ m_keyon_live &= ~(1 << KEYON_CSM);
+
+ // we're active until we're quiet after the release
+ return (m_env_state != (RegisterType::EG_HAS_REVERB ? EG_REVERB : EG_RELEASE) || m_env_attenuation < EG_QUIET);
+}
+
+
+//-------------------------------------------------
+// clock - master clocking function
+//-------------------------------------------------
+
+template<class RegisterType>
+void fm_operator<RegisterType>::clock(uint32_t env_counter, int32_t lfo_raw_pm)
+{
+ // clock the SSG-EG state (OPN/OPNA)
+ if (m_regs.op_ssg_eg_enable(m_opoffs))
+ clock_ssg_eg_state();
+
+ // clock the envelope if on an envelope cycle; env_counter is a x.2 value
+ if (bitfield(env_counter, 0, 2) == 0)
+ clock_envelope(env_counter >> 2);
+
+ // clock the phase
+ clock_phase(lfo_raw_pm);
+}
+
+
+//-------------------------------------------------
+// compute_volume - compute the 14-bit signed
+// volume of this operator, given a phase
+// modulation and an AM LFO offset
+//-------------------------------------------------
+
+template<class RegisterType>
+int32_t fm_operator<RegisterType>::compute_volume(uint32_t phase, uint32_t am_offset) const
+{
+ // the low 10 bits of phase represents a full 2*PI period over
+ // the full sin wave
+
+ // early out if the envelope is effectively off
+ if (m_env_attenuation > EG_QUIET)
+ return 0;
+
+ // get the absolute value of the sin, as attenuation, as a 4.8 fixed point value
+ uint32_t sin_attenuation = m_cache.waveform[phase & (RegisterType::WAVEFORM_LENGTH - 1)];
+
+ // get the attenuation from the evelope generator as a 4.6 value, shifted up to 4.8
+ uint32_t env_attenuation = envelope_attenuation(am_offset) << 2;
+
+ // combine into a 5.8 value, then convert from attenuation to 13-bit linear volume
+ int32_t result = attenuation_to_volume((sin_attenuation & 0x7fff) + env_attenuation);
+
+ // negate if in the negative part of the sin wave (sign bit gives 14 bits)
+ return bitfield(sin_attenuation, 15) ? -result : result;
+}
+
+
+//-------------------------------------------------
+// compute_noise_volume - compute the 14-bit
+// signed noise volume of this operator, given a
+// noise input value and an AM offset
+//-------------------------------------------------
+
+template<class RegisterType>
+int32_t fm_operator<RegisterType>::compute_noise_volume(uint32_t am_offset) const
+{
+ // application manual says the logarithmic transform is not applied here, so we
+ // just use the raw envelope attenuation, inverted (since 0 attenuation should be
+ // maximum), and shift it up from a 10-bit value to an 11-bit value
+ uint32_t result = (envelope_attenuation(am_offset) ^ 0x3ff) << 1;
+
+ // QUESTION: is AM applied still?
+
+ // negate based on the noise state
+ return bitfield(m_regs.noise_state(), 0) ? -result : result;
+}
+
+
+//-------------------------------------------------
+// keyonoff - signal a key on/off event
+//-------------------------------------------------
+
+template<class RegisterType>
+void fm_operator<RegisterType>::keyonoff(uint32_t on, keyon_type type)
+{
+ m_keyon_live = (m_keyon_live & ~(1 << int(type))) | (bitfield(on, 0) << int(type));
+}
+
+
+//-------------------------------------------------
+// start_attack - start the attack phase; called
+// when a keyon happens or when an SSG-EG cycle
+// is complete and restarts
<